@niksbanna/bot-detector 1.0.0 → 1.0.2

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 BotDetectorLib=(()=>{var $=Object.defineProperty;var nt=Object.getOwnPropertyDescriptor;var st=Object.getOwnPropertyNames;var ot=Object.prototype.hasOwnProperty;var at=(g,e,t)=>e in g?$(g,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):g[e]=t;var rt=(g,e)=>{for(var t in e)$(g,t,{get:e[t],enumerable:!0})},ct=(g,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of st(e))!ot.call(g,i)&&i!==t&&$(g,i,{get:()=>e[i],enumerable:!(n=nt(e,i))||n.enumerable});return g};var ht=g=>ct($({},"__esModule",{value:!0}),g);var o=(g,e,t)=>at(g,typeof e!="symbol"?e+"":e,t);var dt={};rt(dt,{AudioContextSignal:()=>I,BotDetector:()=>j,CanvasSignal:()=>P,DOMContentTimingSignal:()=>O,HeadlessSignal:()=>C,InteractionTimingSignal:()=>b,KeyboardPatternSignal:()=>M,MouseMovementSignal:()=>y,NavigatorAnomalySignal:()=>R,PageLoadSignal:()=>A,PermissionsSignal:()=>D,PhantomJSSignal:()=>q,PlaywrightSignal:()=>V,PluginsSignal:()=>S,PuppeteerSignal:()=>B,ScoringEngine:()=>U,ScreenSignal:()=>H,ScrollBehaviorSignal:()=>T,SeleniumSignal:()=>K,Signal:()=>m,Signals:()=>tt,Verdict:()=>z,VerdictEngine:()=>N,WebDriverSignal:()=>E,WebGLSignal:()=>L,createDetector:()=>Z,default:()=>ut,defaultInstantSignals:()=>G,defaultInteractionSignals:()=>Q,defaultSignals:()=>lt,detect:()=>J,detectInstant:()=>et});var m=class{constructor(e={}){this.options=e,this._lastResult=null}get id(){return this.constructor.id}get category(){return this.constructor.category}get weight(){var e;return(e=this.options.weight)!=null?e:this.constructor.weight}get description(){return this.constructor.description}get requiresInteraction(){return this.constructor.requiresInteraction}get lastResult(){return this._lastResult}async detect(){throw new Error(`Signal.detect() must be implemented by ${this.constructor.name}`)}async run(){try{return this._lastResult=await this.detect(),this._lastResult}catch(e){return this._lastResult={triggered:!1,value:null,confidence:0,error:e.message},this._lastResult}}reset(){this._lastResult=null}createResult(e,t=null,n=1){return{triggered:!!e,value:t,confidence:Math.max(0,Math.min(1,n))}}};o(m,"id","base-signal"),o(m,"category","uncategorized"),o(m,"weight",.5),o(m,"description","Base signal class"),o(m,"requiresInteraction",!1);var U=class{constructor(e={}){this.weightOverrides=e.weightOverrides||{},this.maxScore=e.maxScore||100,this._results=new Map}getWeight(e,t){var n;return(n=this.weightOverrides[e])!=null?n:t}addResult(e,t,n){let i=this.getWeight(e,n);this._results.set(e,{...t,weight:i,contribution:t.triggered?i*t.confidence:0})}calculate(){if(this._results.size===0)return 0;let e=0,t=0;for(let[,i]of this._results)e+=i.weight,t+=i.contribution;if(e===0)return 0;let n=t/e*this.maxScore;return Math.round(n*100)/100}getBreakdown(){let e=[];for(let[t,n]of this._results)e.push({signalId:t,triggered:n.triggered,confidence:n.confidence,weight:n.weight,contribution:n.contribution,percentOfScore:this.calculate()>0?(n.contribution/this.calculate()*100).toFixed(1):"0.0"});return e.sort((t,n)=>n.contribution-t.contribution)}getTriggeredSignals(){let e=[];for(let[t,n]of this._results)n.triggered&&e.push(t);return e}getTriggeredCount(){let e=0;for(let[,t]of this._results)t.triggered&&e++;return e}reset(){this._results.clear()}};var z={HUMAN:"human",SUSPICIOUS:"suspicious",BOT:"bot"},F=class F{constructor(e={}){var t,n;this.humanThreshold=(t=e.humanThreshold)!=null?t:F.DEFAULT_THRESHOLDS.human,this.suspiciousThreshold=(n=e.suspiciousThreshold)!=null?n:F.DEFAULT_THRESHOLDS.suspicious,this.instantBotSignals=new Set(e.instantBotSignals||[])}getVerdict(e,t=[]){for(let c of t)if(this.instantBotSignals.has(c))return{verdict:z.BOT,score:e,confidence:"high",reason:`Instant bot signal triggered: ${c}`,triggeredCount:t.length};let n,i,s;return e<this.humanThreshold?(n=z.HUMAN,i=e<10?"high":"medium",s="Low bot score"):e<this.suspiciousThreshold?(n=z.SUSPICIOUS,i="medium",s="Moderate bot indicators detected"):(n=z.BOT,i=e>=75?"high":"medium",s="High accumulation of bot indicators"),{verdict:n,score:e,confidence:i,reason:s,triggeredCount:t.length}}isInstantBotSignal(e){return this.instantBotSignals.has(e)}addInstantBotSignal(e){this.instantBotSignals.add(e)}setThresholds(e){e.human!==void 0&&(this.humanThreshold=e.human),e.suspicious!==void 0&&(this.suspiciousThreshold=e.suspicious)}};o(F,"DEFAULT_THRESHOLDS",{human:20,suspicious:50});var N=F;var j=class g{constructor(e={}){if(this.options=e,this._signals=new Map,this._scoringEngine=new U({weightOverrides:e.weightOverrides}),this._verdictEngine=new N({humanThreshold:e.humanThreshold,suspiciousThreshold:e.suspiciousThreshold,instantBotSignals:e.instantBotSignals}),this._lastDetection=null,this._detectionTimeout=e.detectionTimeout||5e3,this._isRunning=!1,e.signals)for(let t of e.signals)this.registerSignal(t)}registerSignal(e){if(!(e instanceof m))throw new Error("Signal must be an instance of Signal class");let t=e.id;if(this._signals.has(t))throw new Error(`Signal with ID "${t}" is already registered`);return this._signals.set(t,e),this}registerSignals(e){for(let t of e)this.registerSignal(t);return this}unregisterSignal(e){return this._signals.delete(e)}getSignal(e){return this._signals.get(e)}getSignals(){return Array.from(this._signals.values())}getSignalsByCategory(e){return this.getSignals().filter(t=>t.category===e)}async detect(e={}){if(this._isRunning)throw new Error("Detection is already running");this._isRunning=!0,this._scoringEngine.reset();let t=performance.now(),n=new Map;try{let i=this.getSignals().filter(u=>!(e.skipInteractionSignals&&u.requiresInteraction)),s=i.map(async u=>{let l=await Promise.race([u.run(),new Promise(h=>setTimeout(()=>h({triggered:!1,value:null,confidence:0,error:"timeout"}),this._detectionTimeout))]);return{signal:u,result:l}}),c=await Promise.all(s);for(let{signal:u,result:l}of c)n.set(u.id,{...l,category:u.category,weight:u.weight,description:u.description}),this._scoringEngine.addResult(u.id,l,u.weight);let r=this._scoringEngine.calculate(),a=this._scoringEngine.getTriggeredSignals(),p=this._verdictEngine.getVerdict(r,a),d=performance.now()-t;return this._lastDetection={...p,signals:Object.fromEntries(n),breakdown:this._scoringEngine.getBreakdown(),timestamp:Date.now(),detectionTimeMs:Math.round(d),totalSignals:i.length,triggeredSignals:a},this._lastDetection}finally{this._isRunning=!1}}getLastDetection(){return this._lastDetection}getScore(){var e,t;return(t=(e=this._lastDetection)==null?void 0:e.score)!=null?t:0}getTriggeredSignals(){var e,t;return(t=(e=this._lastDetection)==null?void 0:e.triggeredSignals)!=null?t:[]}isRunning(){return this._isRunning}reset(){this._scoringEngine.reset(),this._lastDetection=null;for(let e of this._signals.values())e.reset()}configure(e){(e.humanThreshold!==void 0||e.suspiciousThreshold!==void 0)&&this._verdictEngine.setThresholds({human:e.humanThreshold,suspicious:e.suspiciousThreshold}),e.detectionTimeout!==void 0&&(this._detectionTimeout=e.detectionTimeout)}static withDefaults(e={}){return new g(e)}};var E=class extends m{async detect(){if(navigator.webdriver===!0)return this.createResult(!0,{webdriver:!0},1);let e=Object.getOwnPropertyDescriptor(navigator,"webdriver");if(e&&(e.get||!e.configurable))return this.createResult(!0,{webdriver:"modified",descriptor:{configurable:e.configurable,enumerable:e.enumerable,hasGetter:!!e.get}},.8);try{let t=Object.getPrototypeOf(navigator),n=Object.getOwnPropertyDescriptor(t,"webdriver");if(n&&n.get&&n.get.call(navigator)===!0)return this.createResult(!0,{webdriver:!0,source:"prototype"},1)}catch{}return this.createResult(!1)}};o(E,"id","webdriver"),o(E,"category","environment"),o(E,"weight",1),o(E,"description","Detects navigator.webdriver automation flag");var C=class extends m{async detect(){let e=[],t=0,n=navigator.userAgent||"";n.includes("HeadlessChrome")&&(e.push("headless-ua"),t=Math.max(t,1)),n.includes("Chrome")&&!n.includes("Chromium")&&(typeof window.chrome>"u"?(e.push("missing-chrome-object"),t=Math.max(t,.6)):window.chrome.runtime||(e.push("missing-chrome-runtime"),t=Math.max(t,.4))),navigator.plugins&&navigator.plugins.length===0&&(e.push("no-plugins"),t=Math.max(t,.5)),(!navigator.languages||navigator.languages.length===0)&&(e.push("no-languages"),t=Math.max(t,.6)),window.outerWidth===0&&window.outerHeight===0&&(e.push("zero-outer-dimensions"),t=Math.max(t,.7)),typeof navigator.connection>"u"&&n.includes("Chrome")&&(e.push("missing-connection-api"),t=Math.max(t,.3));try{typeof Notification<"u"&&Notification.permission==="denied"&&window.outerWidth===0&&(e.push("notification-headless-pattern"),t=Math.max(t,.5))}catch{}(window.callPhantom||window._phantom)&&(e.push("phantomjs"),t=Math.max(t,1)),window.__nightmare&&(e.push("nightmare"),t=Math.max(t,1));let i=e.length>0;return e.length>=3&&(t=Math.min(1,t+.2)),this.createResult(i,{indicators:e},t)}};o(C,"id","headless"),o(C,"category","environment"),o(C,"weight",.8),o(C,"description","Detects headless browser indicators");var R=class extends m{async detect(){let e=[],t=0,n=0,i=navigator.userAgent||"",s=navigator.platform||"";n++,s.includes("Win")&&!i.includes("Windows")?(e.push("platform-ua-mismatch-windows"),t+=1):s.includes("Mac")&&!i.includes("Mac")?(e.push("platform-ua-mismatch-mac"),t+=1):s.includes("Linux")&&!i.includes("Linux")&&!i.includes("Android")&&(e.push("platform-ua-mismatch-linux"),t+=1),n++,(!s||s===""||s==="undefined")&&(e.push("empty-platform"),t+=1),n++,navigator.language&&navigator.languages&&(navigator.languages.includes(navigator.language)||(e.push("language-mismatch"),t+=.5)),n++,i.includes("Chrome")&&navigator.vendor!=="Google Inc."?(e.push("vendor-mismatch-chrome"),t+=.5):i.includes("Firefox")&&navigator.vendor!==""?(e.push("vendor-mismatch-firefox"),t+=.5):i.includes("Safari")&&!i.includes("Chrome")&&navigator.vendor!=="Apple Computer, Inc."&&(e.push("vendor-mismatch-safari"),t+=.5),n++,typeof navigator.hardwareConcurrency<"u"&&(navigator.hardwareConcurrency===0||navigator.hardwareConcurrency>128)&&(e.push("suspicious-hardware-concurrency"),t+=.5),n++,typeof navigator.deviceMemory<"u"&&(navigator.deviceMemory===0||navigator.deviceMemory>512)&&(e.push("suspicious-device-memory"),t+=.5),n++;let c=/Android|iPhone|iPad|iPod|Mobile/i.test(i),r=navigator.maxTouchPoints>0;!c&&navigator.maxTouchPoints>5&&(e.push("desktop-high-touch-points"),t+=.3),n++;try{let d=Object.getOwnPropertyDescriptor(Navigator.prototype,"userAgent");d&&d.get&&d.get.toString().includes("native code")===!1&&(e.push("spoofed-user-agent"),t+=1)}catch{}let a=e.length>0,p=Math.min(1,t/Math.max(1,n));return this.createResult(a,{anomalies:e},p)}};o(R,"id","navigator-anomaly"),o(R,"category","environment"),o(R,"weight",.7),o(R,"description","Detects navigator property inconsistencies");var D=class extends m{async detect(){let e=[];if(!navigator.permissions)return this.createResult(!1,{supported:!1},0);try{let i=await navigator.permissions.query({name:"notifications"});if(typeof Notification<"u"){let s=Notification.permission;(s==="granted"&&i.state!=="granted"||s==="denied"&&i.state!=="denied"||s==="default"&&i.state!=="prompt")&&e.push("notification-permission-mismatch")}try{(await navigator.permissions.query({name:"geolocation"})).state==="denied"&&window.outerWidth===0&&e.push("geo-denied-headless")}catch{}try{await navigator.permissions.query({name:"camera"})}catch(s){s.name==="TypeError"&&e.push("camera-permission-error")}}catch(i){i.name!=="TypeError"&&e.push("permissions-query-error")}let t=e.length>0,n=Math.min(1,e.length*.4);return this.createResult(t,{anomalies:e},n)}};o(D,"id","permissions"),o(D,"category","environment"),o(D,"weight",.5),o(D,"description","Detects Permissions API anomalies");var y=class extends m{constructor(e={}){super(e),this._movements=[],this._isTracking=!1,this._trackingDuration=e.trackingDuration||3e3,this._minMovements=e.minMovements||5,this._boundHandler=null}startTracking(){this._isTracking||(this._movements=[],this._isTracking=!0,this._boundHandler=e=>{this._movements.push({x:e.clientX,y:e.clientY,t:performance.now()})},document.addEventListener("mousemove",this._boundHandler,{passive:!0}))}stopTracking(){this._isTracking&&(this._isTracking=!1,this._boundHandler&&(document.removeEventListener("mousemove",this._boundHandler),this._boundHandler=null))}async detect(){let e=[],t=0;this._movements.length===0&&(this.startTracking(),await new Promise(c=>setTimeout(c,this._trackingDuration)),this.stopTracking());let n=this._movements;if(n.length<this._minMovements)return e.push("no-mouse-movement"),t=Math.max(t,.6),this.createResult(!0,{anomalies:e,movements:n.length},t);let i=this._analyzeMovements(n);i.teleportCount>0&&(e.push("mouse-teleportation"),t=Math.max(t,.7)),i.linearPathRatio>.9&&(e.push("linear-path"),t=Math.max(t,.8)),i.velocityVariance<.01&&n.length>10&&(e.push("constant-velocity"),t=Math.max(t,.7)),i.accelerationChanges===0&&n.length>10&&(e.push("no-acceleration-variance"),t=Math.max(t,.6)),i.timingVariance<1&&n.length>10&&(e.push("robotic-timing"),t=Math.max(t,.8));let s=e.length>0;return this.createResult(s,{anomalies:e,movementCount:n.length,analysis:i},t)}_analyzeMovements(e){if(e.length<3)return{teleportCount:0,linearPathRatio:0,velocityVariance:0,accelerationChanges:0,timingVariance:0};let t=0,n=[],i=[],s=[];for(let l=1;l<e.length;l++){let h=e[l-1],f=e[l],x=f.x-h.x,_=f.y-h.y,w=f.t-h.t;if(w===0)continue;let k=Math.sqrt(x*x+_*_),v=k/w;n.push(v),i.push(Math.atan2(_,x)),s.push(w),k>300&&w<10&&t++}let c=n.reduce((l,h)=>l+h,0)/n.length,r=n.reduce((l,h)=>l+Math.pow(h-c,2),0)/n.length,a=0;if(i.length>1){let l=0;for(let h=1;h<i.length;h++)Math.abs(i[h]-i[h-1])<.1&&l++;a=l/(i.length-1)}let p=s.reduce((l,h)=>l+h,0)/s.length,d=s.reduce((l,h)=>l+Math.pow(h-p,2),0)/s.length,u=0;for(let l=1;l<n.length;l++)(n[l]-n[l-1])*(n[l-1]-(n[l-2]||0))<0&&u++;return{teleportCount:t,linearPathRatio:a,velocityVariance:r,accelerationChanges:u,timingVariance:d}}reset(){super.reset(),this.stopTracking(),this._movements=[]}};o(y,"id","mouse-movement"),o(y,"category","behavior"),o(y,"weight",.9),o(y,"description","Detects non-human mouse movement patterns"),o(y,"requiresInteraction",!0);var M=class extends m{constructor(e={}){super(e),this._keystrokes=[],this._isTracking=!1,this._trackingDuration=e.trackingDuration||5e3,this._minKeystrokes=e.minKeystrokes||10,this._boundKeydownHandler=null,this._boundKeyupHandler=null}startTracking(){this._isTracking||(this._keystrokes=[],this._isTracking=!0,this._boundKeydownHandler=e=>{this._keystrokes.push({type:"down",key:e.key,code:e.code,t:performance.now()})},this._boundKeyupHandler=e=>{this._keystrokes.push({type:"up",key:e.key,code:e.code,t:performance.now()})},document.addEventListener("keydown",this._boundKeydownHandler,{passive:!0}),document.addEventListener("keyup",this._boundKeyupHandler,{passive:!0}))}stopTracking(){this._isTracking&&(this._isTracking=!1,this._boundKeydownHandler&&(document.removeEventListener("keydown",this._boundKeydownHandler),this._boundKeydownHandler=null),this._boundKeyupHandler&&(document.removeEventListener("keyup",this._boundKeyupHandler),this._boundKeyupHandler=null))}async detect(){let e=[],t=0;this._keystrokes.length===0&&(this.startTracking(),await new Promise(r=>setTimeout(r,this._trackingDuration)),this.stopTracking());let n=this._keystrokes,i=n.filter(r=>r.type==="down");if(i.length<this._minKeystrokes)return this.createResult(!1,{reason:"insufficient-data",keystrokes:i.length},0);let s=this._analyzeKeystrokes(n);s.avgInterKeystrokeTime<50&&i.length>20&&(e.push("inhuman-speed"),t=Math.max(t,.9)),s.timingVariance<5&&i.length>15&&(e.push("robotic-timing"),t=Math.max(t,.8)),s.missingKeyups>i.length*.5&&(e.push("missing-keyups"),t=Math.max(t,.7)),s.holdTimeVariance<2&&s.holdTimes.length>10&&(e.push("constant-hold-time"),t=Math.max(t,.6)),s.sequentialKeys>i.length*.8&&i.length>10&&(e.push("sequential-input"),t=Math.max(t,.5)),s.rhythmScore<.1&&i.length>20&&(e.push("no-rhythm-variation"),t=Math.max(t,.6));let c=e.length>0;return this.createResult(c,{anomalies:e,keystrokeCount:i.length,analysis:s},t)}_analyzeKeystrokes(e){let t=e.filter(h=>h.type==="down"),n=e.filter(h=>h.type==="up");if(t.length<2)return{avgInterKeystrokeTime:1/0,timingVariance:1/0,missingKeyups:0,holdTimeVariance:1/0,holdTimes:[],sequentialKeys:0,rhythmScore:1};let i=[];for(let h=1;h<t.length;h++)i.push(t[h].t-t[h-1].t);let s=i.reduce((h,f)=>h+f,0)/i.length,c=i.reduce((h,f)=>h+Math.pow(f-s,2),0)/i.length,r=[];for(let h of t){let f=n.find(x=>x.key===h.key&&x.t>h.t);f&&r.push(f.t-h.t)}let a=r.length>0?r.reduce((h,f)=>h+f,0)/r.length:0,p=r.length>0?r.reduce((h,f)=>h+Math.pow(f-a,2),0)/r.length:1/0,d=t.length-r.length,u=0;for(let h=1;h<t.length;h++){let f=t[h-1].key.charCodeAt(0),x=t[h].key.charCodeAt(0);Math.abs(x-f)===1&&u++}let l=0;if(i.length>5){let h=[...i].sort((_,w)=>_-w),f=h[Math.floor(h.length/2)];l=i.filter(_=>Math.abs(_-f)>f*.3).length/i.length}return{avgInterKeystrokeTime:s,timingVariance:c,missingKeyups:d,holdTimeVariance:p,holdTimes:r,sequentialKeys:u,rhythmScore:l}}reset(){super.reset(),this.stopTracking(),this._keystrokes=[]}};o(M,"id","keyboard-pattern"),o(M,"category","behavior"),o(M,"weight",.8),o(M,"description","Detects non-human keystroke patterns"),o(M,"requiresInteraction",!0);var b=class extends m{constructor(e={}){super(e),this._pageLoadTime=performance.now(),this._firstInteractionTime=null,this._interactions=[],this._isTracking=!1,this._trackingDuration=e.trackingDuration||5e3,this._boundHandler=null}startTracking(){if(this._isTracking)return;this._interactions=[],this._isTracking=!0;let e=["click","mousedown","touchstart","keydown","scroll"];this._boundHandler=t=>{let n=performance.now();this._firstInteractionTime===null&&(this._firstInteractionTime=n),this._interactions.push({type:t.type,t:n,timeSinceLoad:n-this._pageLoadTime})};for(let t of e)document.addEventListener(t,this._boundHandler,{passive:!0,capture:!0})}stopTracking(){if(!this._isTracking)return;this._isTracking=!1;let e=["click","mousedown","touchstart","keydown","scroll"];if(this._boundHandler){for(let t of e)document.removeEventListener(t,this._boundHandler,{capture:!0});this._boundHandler=null}}async detect(){let e=[],t=0;!this._isTracking&&this._interactions.length===0&&(this.startTracking(),await new Promise(r=>setTimeout(r,this._trackingDuration)),this.stopTracking());let n=this._interactions;if(n.length===0)return this.createResult(!1,{reason:"no-interactions"},0);let i=n[0];if(i.timeSinceLoad<100?(e.push("instant-interaction"),t=Math.max(t,.9)):i.timeSinceLoad<300&&(e.push("very-fast-interaction"),t=Math.max(t,.6)),n.length>3){let r=[];for(let l=1;l<n.length;l++)r.push(n[l].t-n[l-1].t);let a=r.reduce((l,h)=>l+h,0)/r.length;r.reduce((l,h)=>l+Math.pow(h-a,2),0)/r.length<10&&n.length>5&&(e.push("robotic-intervals"),t=Math.max(t,.8));let d=50,u=0;for(let l of r)l<d&&u++;u>r.length*.7&&(e.push("burst-interactions"),t=Math.max(t,.7))}let s=n.map(r=>r.type).join(",");if(n.length>=6){let r=Math.floor(n.length/2),a=n.slice(0,r).map(d=>d.type).join(","),p=n.slice(r,r*2).map(d=>d.type).join(",");a===p&&a.length>0&&(e.push("repeated-sequence"),t=Math.max(t,.6))}let c=e.length>0;return this.createResult(c,{anomalies:e,interactionCount:n.length,timeToFirstInteraction:i.timeSinceLoad,firstInteractionType:i.type},t)}reset(){super.reset(),this.stopTracking(),this._pageLoadTime=performance.now(),this._firstInteractionTime=null,this._interactions=[]}};o(b,"id","interaction-timing"),o(b,"category","behavior"),o(b,"weight",.6),o(b,"description","Detects suspicious interaction timing"),o(b,"requiresInteraction",!0);var T=class extends m{constructor(e={}){super(e),this._scrollEvents=[],this._isTracking=!1,this._trackingDuration=e.trackingDuration||3e3,this._boundHandler=null}startTracking(){this._isTracking||(this._scrollEvents=[],this._isTracking=!0,this._boundHandler=()=>{this._scrollEvents.push({scrollY:window.scrollY,scrollX:window.scrollX,t:performance.now()})},window.addEventListener("scroll",this._boundHandler,{passive:!0}))}stopTracking(){this._isTracking&&(this._isTracking=!1,this._boundHandler&&(window.removeEventListener("scroll",this._boundHandler),this._boundHandler=null))}async detect(){let e=[],t=0;this._scrollEvents.length===0&&(this.startTracking(),await new Promise(c=>setTimeout(c,this._trackingDuration)),this.stopTracking());let n=this._scrollEvents;if(n.length<3)return this.createResult(!1,{reason:"insufficient-scroll-data",scrollEvents:n.length},0);let i=this._analyzeScrollPatterns(n);i.instantJumps>0&&(e.push("instant-scroll-jumps"),t=Math.max(t,.7)),i.velocityVariance<.1&&n.length>10&&(e.push("constant-scroll-velocity"),t=Math.max(t,.6)),i.momentumEvents===0&&n.length>5&&(e.push("no-scroll-momentum"),t=Math.max(t,.5)),i.intervalVariance<5&&n.length>10&&(e.push("robotic-scroll-timing"),t=Math.max(t,.7)),i.scrollDirections===1&&Math.abs(i.totalScrollY)>1e3&&i.velocityVariance<1&&(e.push("one-dimensional-scroll"),t=Math.max(t,.4)),i.exactPositionScrolls>2&&(e.push("exact-position-scrolls"),t=Math.max(t,.6));let s=e.length>0;return this.createResult(s,{anomalies:e,scrollEventCount:n.length,analysis:i},t)}_analyzeScrollPatterns(e){if(e.length<2)return{instantJumps:0,velocityVariance:0,momentumEvents:0,intervalVariance:0,scrollDirections:0,totalScrollY:0,exactPositionScrolls:0};let t=0,n=0,i=[],s=[],c=!1,r=!1,a=0,p=[0,100,200,300,400,500,600,800,1e3];for(let _=1;_<e.length;_++){let w=e[_-1],k=e[_],v=k.scrollY-w.scrollY,W=k.scrollX-w.scrollX,Y=k.t-w.t;if(s.push(Y),Math.abs(v)>0&&(c=!0),Math.abs(W)>0&&(r=!0),Y===0)continue;let X=Math.sqrt(v*v+W*W)/Y;if(i.push(X),Math.abs(v)+Math.abs(W)>200&&Y<20&&t++,_>1&&i.length>1){let it=i[i.length-2];X<it*.9&&X>0&&n++}p.includes(Math.round(k.scrollY))&&a++}let d=i.length>0?i.reduce((_,w)=>_+w,0)/i.length:0,u=i.length>0?i.reduce((_,w)=>_+Math.pow(w-d,2),0)/i.length:0,l=s.reduce((_,w)=>_+w,0)/s.length,h=s.reduce((_,w)=>_+Math.pow(w-l,2),0)/s.length,f=0;c&&f++,r&&f++;let x=e[e.length-1].scrollY-e[0].scrollY;return{instantJumps:t,velocityVariance:u,momentumEvents:n,intervalVariance:h,scrollDirections:f,totalScrollY:x,exactPositionScrolls:a}}reset(){super.reset(),this.stopTracking(),this._scrollEvents=[]}};o(T,"id","scroll-behavior"),o(T,"category","behavior"),o(T,"weight",.5),o(T,"description","Detects programmatic scroll patterns"),o(T,"requiresInteraction",!0);var S=class extends m{async detect(){let e=[],t=0,n=navigator.plugins,i=navigator.mimeTypes;if(!n)return e.push("no-plugins-object"),t=Math.max(t,.6),this.createResult(!0,{anomalies:e},t);n.length===0&&(e.push("empty-plugins"),t=Math.max(t,.5));let s=navigator.userAgent||"";if(s.includes("Chrome")&&!s.includes("Chromium")&&!Array.from(n).some(p=>p.name.includes("PDF")||p.name.includes("Chromium PDF"))&&n.length===0&&(e.push("chrome-missing-pdf-plugin"),t=Math.max(t,.4)),n.length>0&&i){let a=0;for(let p=0;p<n.length;p++)a+=n[p].length||0;i.length===0&&a>0&&(e.push("mimetypes-mismatch"),t=Math.max(t,.5))}if(n.length>1){let a=Array.from(n).map(d=>d.name);new Set(a).size<a.length&&(e.push("duplicate-plugins"),t=Math.max(t,.6))}try{let a=Object.getOwnPropertyDescriptor(Navigator.prototype,"plugins");a&&a.get&&(a.get.toString().includes("[native code]")||(e.push("plugins-getter-overridden"),t=Math.max(t,.7)))}catch{}!/Android|iPhone|iPad|iPod|Mobile/i.test(s)&&n.length===1&&(e.push("minimal-plugins"),t=Math.max(t,.3));let r=e.length>0;return this.createResult(r,{anomalies:e,pluginCount:n.length,mimeTypeCount:(i==null?void 0:i.length)||0},t)}};o(S,"id","plugins"),o(S,"category","fingerprint"),o(S,"weight",.6),o(S,"description","Detects browser plugin anomalies");var L=class extends m{async detect(){let e=[],t=0,n=document.createElement("canvas"),i=null;try{i=n.getContext("webgl")||n.getContext("experimental-webgl")}catch{e.push("webgl-error"),t=Math.max(t,.5)}if(!i)return e.push("webgl-unavailable"),t=Math.max(t,.4),this.createResult(!0,{anomalies:e},t);let s=i.getExtension("WEBGL_debug_renderer_info"),c="",r="";s&&(c=i.getParameter(s.UNMASKED_VENDOR_WEBGL)||"",r=i.getParameter(s.UNMASKED_RENDERER_WEBGL)||""),!c&&!r&&(e.push("no-webgl-renderer-info"),t=Math.max(t,.6));let a=["swiftshader","llvmpipe","software","mesa","google swiftshader","vmware","virtualbox"],p=r.toLowerCase();for(let x of a)if(p.includes(x)){e.push(`suspicious-renderer-${x.replace(/\s+/g,"-")}`),t=Math.max(t,.7);break}c&&r&&(p.includes("nvidia")&&!c.toLowerCase().includes("nvidia")&&(e.push("vendor-renderer-mismatch"),t=Math.max(t,.6)),(p.includes("amd")||p.includes("radeon"))&&!c.toLowerCase().includes("amd")&&!c.toLowerCase().includes("ati")&&(e.push("vendor-renderer-mismatch"),t=Math.max(t,.6)));let d=i.getSupportedExtensions()||[];d.length<5&&(e.push("few-webgl-extensions"),t=Math.max(t,.4));let u=i.getParameter(i.MAX_TEXTURE_SIZE),l=i.getParameter(i.MAX_VIEWPORT_DIMS);(u<1024||u>65536)&&(e.push("unrealistic-max-texture"),t=Math.max(t,.5));try{i.clearColor(0,0,0,1),i.clear(i.COLOR_BUFFER_BIT);let x=new Uint8Array(4);i.readPixels(0,0,1,1,i.RGBA,i.UNSIGNED_BYTE,x),x[3]!==255&&(e.push("webgl-render-failure"),t=Math.max(t,.6))}catch{e.push("webgl-render-error"),t=Math.max(t,.5)}let h=i.getExtension("WEBGL_lose_context");h&&h.loseContext();let f=e.length>0;return this.createResult(f,{anomalies:e,vendor:c,renderer:r,extensionCount:d.length,maxTextureSize:u},t)}};o(L,"id","webgl"),o(L,"category","fingerprint"),o(L,"weight",.7),o(L,"description","Detects WebGL rendering anomalies");var P=class extends m{async detect(){let e=[],t=0;try{let i=document.createElement("canvas");i.width=200,i.height=50;let s=i.getContext("2d");if(!s)return e.push("canvas-context-unavailable"),t=Math.max(t,.5),this.createResult(!0,{anomalies:e},t);s.textBaseline="alphabetic",s.font="14px Arial",s.fillStyle="#f60",s.fillRect(0,0,200,50),s.fillStyle="#069",s.fillText("Bot Detection Test \u{1F916}",2,15),s.fillStyle="rgba(102, 204, 0, 0.7)",s.fillText("Canvas Fingerprint",4,30),s.beginPath(),s.arc(100,25,10,0,Math.PI*2,!0),s.closePath(),s.fill();let c=i.toDataURL();s.clearRect(0,0,200,50),s.fillStyle="#f60",s.fillRect(0,0,200,50),s.fillStyle="#069",s.fillText("Bot Detection Test \u{1F916}",2,15),s.fillStyle="rgba(102, 204, 0, 0.7)",s.fillText("Canvas Fingerprint",4,30),s.beginPath(),s.arc(100,25,10,0,Math.PI*2,!0),s.closePath(),s.fill();let r=i.toDataURL();c!==r&&(e.push("canvas-randomized"),t=Math.max(t,.6)),c.length<1e3&&(e.push("canvas-possibly-blank"),t=Math.max(t,.4));let a=document.createElement("canvas");a.width=200,a.height=50;let p=a.toDataURL();c===p&&(e.push("canvas-rendering-blocked"),t=Math.max(t,.7));try{i.toDataURL.toString().includes("[native code]")||(e.push("toDataURL-overridden"),t=Math.max(t,.8))}catch{}let u=s.getImageData(0,0,200,50).data,l=!0,h=[u[0],u[1],u[2],u[3]];for(let f=4;f<u.length;f+=4)if(u[f]!==h[0]||u[f+1]!==h[1]||u[f+2]!==h[2]){l=!1;break}l&&(e.push("uniform-pixel-data"),t=Math.max(t,.6))}catch{e.push("canvas-error"),t=Math.max(t,.4)}let n=e.length>0;return this.createResult(n,{anomalies:e},t)}};o(P,"id","canvas"),o(P,"category","fingerprint"),o(P,"weight",.5),o(P,"description","Detects canvas fingerprint anomalies");var I=class extends m{async detect(){let e=[],t=0,n=window.AudioContext||window.webkitAudioContext;if(!n)return e.push("audio-context-unavailable"),t=Math.max(t,.4),this.createResult(!0,{anomalies:e},t);let i=null,s=null,c=null;try{i=new n;let a=i.sampleRate;if(a!==44100&&a!==48e3&&a!==96e3&&(e.push("unusual-sample-rate"),t=Math.max(t,.3)),s=i.createOscillator(),c=i.createAnalyser(),!s||!c)e.push("audio-nodes-unavailable"),t=Math.max(t,.5);else{let d=c.fftSize,u=i.destination;(!u||u.maxChannelCount===0)&&(e.push("no-audio-destination"),t=Math.max(t,.6)),u&&u.maxChannelCount<2&&(e.push("mono-audio-only"),t=Math.max(t,.3))}try{n.toString().includes("[native code]")||(e.push("audio-context-overridden"),t=Math.max(t,.7))}catch{}try{if(i.state==="suspended"&&await i.resume().catch(()=>{}),i.state==="running"){let d=i.createOscillator(),u=i.createGain(),l=i.createScriptProcessor?i.createScriptProcessor(4096,1,1):null;l&&(d.type="triangle",d.frequency.value=1e4,u.gain.value=0,d.connect(u),u.connect(l),l.connect(i.destination),d.start(0),await new Promise(h=>setTimeout(h,50)),d.stop(),d.disconnect(),u.disconnect(),l.disconnect())}}catch{e.push("audio-fingerprint-blocked"),t=Math.max(t,.4)}window.OfflineAudioContext||window.webkitOfflineAudioContext||(e.push("offline-audio-context-unavailable"),t=Math.max(t,.3))}catch{e.push("audio-context-error"),t=Math.max(t,.4)}finally{if(s)try{s.disconnect()}catch{}if(c)try{c.disconnect()}catch{}if(i)try{i.close()}catch{}}let r=e.length>0;return this.createResult(r,{anomalies:e},t)}};o(I,"id","audio-context"),o(I,"category","fingerprint"),o(I,"weight",.5),o(I,"description","Detects AudioContext anomalies");var H=class extends m{async detect(){let e=[],t=0,n=window.screen;if(!n)return e.push("no-screen-object"),t=Math.max(t,.6),this.createResult(!0,{anomalies:e},t);let i=n.width,s=n.height,c=n.availWidth,r=n.availHeight,a=n.colorDepth,p=n.pixelDepth,d=window.outerWidth,u=window.outerHeight,l=window.innerWidth,h=window.innerHeight;(d===0||u===0)&&(e.push("zero-outer-dimensions"),t=Math.max(t,.8)),(l===0||h===0)&&(e.push("zero-inner-dimensions"),t=Math.max(t,.7));let f=navigator.userAgent||"";!/Android|iPhone|iPad|iPod|Mobile/i.test(f)&&(i<640||s<480)&&(e.push("very-small-screen"),t=Math.max(t,.5)),(i>7680||s>4320)&&(e.push("unrealistic-screen-size"),t=Math.max(t,.4));let _=[{w:800,h:600},{w:1024,h:768},{w:1920,h:1080}];for(let v of _)if(i===v.w&&s===v.h&&d===v.w&&u===v.h){e.push("headless-default-dimensions"),t=Math.max(t,.5);break}(c>i||r>s)&&(e.push("available-exceeds-total"),t=Math.max(t,.7)),(d>i||u>s)&&(e.push("window-exceeds-screen"),t=Math.max(t,.6)),a!==24&&a!==32&&a!==30&&a!==48&&(e.push("unusual-color-depth"),t=Math.max(t,.3)),a!==p&&(e.push("depth-mismatch"),t=Math.max(t,.3));let w=window.devicePixelRatio;if(w===0||w===void 0?(e.push("missing-device-pixel-ratio"),t=Math.max(t,.5)):(w<.5||w>5)&&(e.push("unusual-device-pixel-ratio"),t=Math.max(t,.4)),n.orientation){let v=n.orientation.type,W=n.orientation.angle;v.includes("landscape")&&i<s&&(e.push("orientation-dimension-mismatch"),t=Math.max(t,.4)),v.includes("portrait")&&i>s&&(e.push("orientation-dimension-mismatch"),t=Math.max(t,.4))}l===d&&h===u&&d>0&&u>0&&(e.push("no-browser-chrome"),t=Math.max(t,.5));let k=e.length>0;return this.createResult(k,{anomalies:e,dimensions:{screen:{width:i,height:s},available:{width:c,height:r},window:{outer:{width:d,height:u},inner:{width:l,height:h}},colorDepth:a,devicePixelRatio:w}},t)}};o(H,"id","screen"),o(H,"category","fingerprint"),o(H,"weight",.4),o(H,"description","Detects unusual screen dimensions");var A=class extends m{async detect(){let e=[],t=0;if(!window.performance||!performance.timing){if(performance.getEntriesByType){let v=performance.getEntriesByType("navigation");if(v.length>0)return this._analyzeNavigationTiming(v[0])}return e.push("no-performance-api"),t=Math.max(t,.3),this.createResult(!0,{anomalies:e},t)}let n=performance.timing,i=n.navigationStart,s=n.domContentLoadedEventEnd-i,c=n.domComplete-i,r=n.loadEventEnd-i,a=n.domainLookupEnd-n.domainLookupStart,p=n.connectEnd-n.connectStart,d=n.responseEnd-n.requestStart,u=n.domComplete-n.domLoading;s>0&&s<10&&(e.push("instant-dom-content-loaded"),t=Math.max(t,.7)),a===0&&p===0&&d<5&&(e.push("zero-network-timing"),t=Math.max(t,.4)),(s<0||c<0||r<0)&&(e.push("negative-timing"),t=Math.max(t,.8)),n.domContentLoadedEventEnd>0&&n.loadEventEnd>0&&n.domContentLoadedEventEnd>n.loadEventEnd&&(e.push("timing-order-violation"),t=Math.max(t,.7)),u>3e4&&(e.push("excessive-dom-processing"),t=Math.max(t,.3));let l=n.domContentLoadedEventStart-n.responseEnd;l>0&&l<5&&(e.push("instant-script-execution"),t=Math.max(t,.4));let h=performance.now(),f=performance.now();h===f&&h>0&&(e.push("frozen-performance-now"),t=Math.max(t,.6));let x=Date.now(),_=performance.now(),w=Date.now();Math.abs(w-x-(performance.now()-_))>100&&(e.push("timing-inconsistency"),t=Math.max(t,.5));let k=e.length>0;return this.createResult(k,{anomalies:e,timings:{domContentLoaded:s,domComplete:c,loadComplete:r,dnsLookup:a,tcpConnection:p,serverResponse:d,domProcessing:u}},t)}_analyzeNavigationTiming(e){let t=[],n=0,i=e.domContentLoadedEventEnd,s=e.loadEventEnd,c=e.domainLookupEnd-e.domainLookupStart,r=e.responseEnd-e.requestStart;i>0&&i<10&&(t.push("instant-dom-content-loaded"),n=Math.max(n,.7)),c===0&&r===0&&(t.push("zero-network-timing"),n=Math.max(n,.4));let a=t.length>0;return this.createResult(a,{anomalies:t,timings:{domContentLoaded:i,loadComplete:s,dnsLookup:c,serverResponse:r}},n)}};o(A,"id","page-load"),o(A,"category","timing"),o(A,"weight",.5),o(A,"description","Detects suspicious page load timing");var O=class extends m{constructor(e={}){super(e),this._domContentLoadedTime=null,this._documentReadyState=document.readyState,this._captureTime=performance.now(),document.readyState==="loading"&&document.addEventListener("DOMContentLoaded",()=>{this._domContentLoadedTime=performance.now()})}async detect(){let e=[],t=0,n=performance.now(),i=document.readyState,s=0,c=0,r=0;if(performance.getEntriesByType){let p=performance.getEntriesByType("resource");s=p.length;for(let d of p)c+=d.duration,d.initiatorType==="script"&&d.name.startsWith("http")&&r++}s===0&&i==="complete"&&(e.push("no-resources-loaded"),t=Math.max(t,.4)),this._domContentLoadedTime&&this._domContentLoadedTime<50&&s===0&&(e.push("instant-ready-no-resources"),t=Math.max(t,.6)),document.hidden&&this._documentReadyState==="loading"&&(e.push("hidden-at-load"),t=Math.max(t,.3)),typeof document.visibilityState>"u"&&(e.push("no-visibility-api"),t=Math.max(t,.4));try{let p=performance.now(),d=document.createElement("div");d.id="__bot_detection_test__",document.body.appendChild(d);let u=performance.now();document.body.removeChild(d);let l=performance.now(),h=u-p,f=l-u;h===0&&f===0&&(e.push("instant-dom-operations"),t=Math.max(t,.5))}catch{document.body||(e.push("no-document-body"),t=Math.max(t,.4))}if(typeof MutationObserver>"u"&&(e.push("no-mutation-observer"),t=Math.max(t,.5)),typeof requestAnimationFrame>"u"&&(e.push("no-request-animation-frame"),t=Math.max(t,.5)),performance.getEntriesByType){let p=performance.getEntriesByType("paint");!p.find(l=>l.name==="first-paint")&&i==="complete"&&n>1e3&&(e.push("no-first-paint"),t=Math.max(t,.4)),!p.find(l=>l.name==="first-contentful-paint")&&i==="complete"&&n>1e3&&(e.push("no-first-contentful-paint"),t=Math.max(t,.4))}typeof IntersectionObserver>"u"&&(e.push("no-intersection-observer"),t=Math.max(t,.4));let a=e.length>0;return this.createResult(a,{anomalies:e,metrics:{readyState:i,resourceCount:s,externalScriptCount:r,domContentLoadedTime:this._domContentLoadedTime,documentHidden:document.hidden}},t)}};o(O,"id","dom-content-timing"),o(O,"category","timing"),o(O,"weight",.4),o(O,"description","Analyzes DOM content loaded timing patterns");var B=class extends m{async detect(){let e=[],t=0;window.__puppeteer_evaluation_script__&&(e.push("puppeteer-evaluation-script"),t=Math.max(t,1));let n=["__puppeteer_evaluation_script__","__puppeteer","puppeteer"];for(let r of n)r in window&&(e.push(`global-${r}`),t=Math.max(t,1));(navigator.userAgent||"").includes("HeadlessChrome")&&(e.push("headless-chrome-ua"),t=Math.max(t,.9)),(window.cdc_adoQpoasnfa76pfcZLmcfl_Array||window.cdc_adoQpoasnfa76pfcZLmcfl_Promise||window.cdc_adoQpoasnfa76pfcZLmcfl_Symbol)&&(e.push("cdp-artifacts"),t=Math.max(t,1));try{window.eval.toString().includes("puppeteer")&&(e.push("eval-puppeteer"),t=Math.max(t,.9))}catch{}try{throw new Error("stack trace test")}catch(r){let a=r.stack||"";(a.includes("puppeteer")||a.includes("pptr"))&&(e.push("stack-trace-puppeteer"),t=Math.max(t,.8))}window.innerWidth===800&&window.innerHeight===600&&(e.push("default-viewport"),t=Math.max(t,.3)),navigator.webdriver===!0&&(e.push("webdriver-flag"),t=Math.max(t,.9)),Object.keys(window).filter(r=>r.startsWith("__")&&typeof window[r]=="function").length>3&&(e.push("suspicious-bindings"),t=Math.max(t,.5)),typeof window.chrome<"u"&&(!window.chrome.runtime||!window.chrome.runtime.id)&&(e.push("incomplete-chrome-object"),t=Math.max(t,.4));let c=e.length>0;return this.createResult(c,{indicators:e},t)}};o(B,"id","puppeteer"),o(B,"category","automation"),o(B,"weight",1),o(B,"description","Detects Puppeteer automation artifacts");var V=class extends m{async detect(){let e=[],t=0;window.__playwright&&(e.push("playwright-namespace"),t=Math.max(t,1));let n=["__playwright","__pw_manual","__pwInitScripts","playwright"];for(let c of n)c in window&&(e.push(`global-${c}`),t=Math.max(t,1));window.__playwright__binding__&&(e.push("playwright-binding"),t=Math.max(t,1));let i=navigator.userAgent||"";(i.includes("Playwright")||i.includes("HeadlessChrome"))&&(e.push("playwright-ua-marker"),t=Math.max(t,i.includes("Playwright")?1:.7)),navigator.webdriver===!0&&(e.push("webdriver-flag"),t=Math.max(t,.8));try{Object.keys(window).filter(a=>a.startsWith("__pw")).length>0&&(e.push("pw-bindings"),t=Math.max(t,1))}catch{}typeof window.__pw_date_intercepted<"u"&&(e.push("date-interception"),t=Math.max(t,.9)),window.__pw_geolocation__&&(e.push("geolocation-mock"),t=Math.max(t,.9)),window.__pw_permissions__&&(e.push("permissions-override"),t=Math.max(t,.9)),window.__cdpSession__&&(e.push("cdp-session"),t=Math.max(t,.8));try{throw new Error("stack trace test")}catch(c){let r=c.stack||"";(r.includes("playwright")||r.includes("__pw"))&&(e.push("stack-trace-playwright"),t=Math.max(t,.8))}try{let r=new Date().toLocaleString();window.__pwTimezone__&&(e.push("timezone-mock"),t=Math.max(t,.8))}catch{}let s=e.length>0;return this.createResult(s,{indicators:e},t)}};o(V,"id","playwright"),o(V,"category","automation"),o(V,"weight",1),o(V,"description","Detects Playwright automation artifacts");var K=class extends m{async detect(){let e=[],t=0;navigator.webdriver===!0&&(e.push("webdriver-flag"),t=Math.max(t,1));let n=["_selenium","callSelenium","_Selenium_IDE_Recorder","__selenium_evaluate","__selenium_unwrap","__webdriver_evaluate","__webdriver_unwrap","__webdriver_script_function","__webdriver_script_func","__fxdriver_evaluate","__fxdriver_unwrap","webdriver"];for(let a of n)a in window&&(e.push(`global-${a}`),t=Math.max(t,1));let i=["__webdriver_script_fn","__driver_evaluate","__webdriver_evaluate","__selenium_evaluate","__fxdriver_evaluate","__driver_unwrap","__webdriver_unwrap","__selenium_unwrap","__fxdriver_unwrap"];for(let a of i)a in document&&(e.push(`document-${a}`),t=Math.max(t,1));Object.keys(window).filter(a=>a.startsWith("$cdc_")||a.startsWith("$wdc_")||a.startsWith("$chrome_asyncScriptInfo")).length>0&&(e.push("chromedriver-variables"),t=Math.max(t,1)),(window.webdriverCallback||document.documentElement.getAttribute("webdriver"))&&(e.push("geckodriver-artifacts"),t=Math.max(t,1));try{let a=document.documentElement;(a.hasAttribute("webdriver")||a.getAttribute("selenium")||a.getAttribute("driver"))&&(e.push("document-webdriver-attr"),t=Math.max(t,1))}catch{}(window.selenium||window.sideex)&&(e.push("selenium-ide"),t=Math.max(t,1));try{let a=Object.getOwnPropertyDescriptor(Navigator.prototype,"webdriver");a&&a.get&&(a.get.toString().includes("[native code]")||(e.push("webdriver-getter-modified"),t=Math.max(t,.7)))}catch{}(window.domAutomation||window.domAutomationController)&&(e.push("dom-automation"),t=Math.max(t,1)),window.awesomium&&(e.push("awesomium"),t=Math.max(t,.9)),window.external&&window.external.toString().includes("Selenium")&&(e.push("external-selenium"),t=Math.max(t,1));let r=e.length>0;return this.createResult(r,{indicators:e},t)}};o(K,"id","selenium"),o(K,"category","automation"),o(K,"weight",1),o(K,"description","Detects Selenium WebDriver artifacts");var q=class extends m{async detect(){let e=[],t=0;window.callPhantom&&(e.push("callPhantom"),t=Math.max(t,1)),window._phantom&&(e.push("_phantom"),t=Math.max(t,1)),window.phantom&&(e.push("phantom"),t=Math.max(t,1));let n=navigator.userAgent||"";n.includes("PhantomJS")&&(e.push("phantomjs-ua"),t=Math.max(t,1)),window.__phantomas&&(e.push("phantomas"),t=Math.max(t,1)),window.__casper&&(e.push("casperjs"),t=Math.max(t,1)),window.casper&&(e.push("casper-global"),t=Math.max(t,1)),window.slimer&&(e.push("slimerjs"),t=Math.max(t,1)),window.__nightmare&&(e.push("nightmare"),t=Math.max(t,1)),window.nightmare&&(e.push("nightmare-global"),t=Math.max(t,1));try{let c=Function.prototype.toString.call(Function);(c.includes("phantom")||c.includes("Phantom"))&&(e.push("function-prototype-phantom"),t=Math.max(t,.8))}catch{}try{throw new Error("test")}catch(c){(c.stack||"").includes("phantom")&&(e.push("stack-trace-phantom"),t=Math.max(t,.9))}navigator.plugins&&navigator.plugins.length===0&&e.length>0&&(e.push("no-plugins-phantom"),t=Math.max(t,.5));let i=["__PHANTOM__","PHANTOM","Buffer","process"];for(let c of i)c in window&&c!=="Buffer"&&c!=="process"&&(e.push(`phantom-prop-${c.toLowerCase()}`),t=Math.max(t,.9));n.includes("QtWebKit")&&(e.push("qtwebkit"),t=Math.max(t,.7));let s=e.length>0;return this.createResult(s,{indicators:e},t)}};o(q,"id","phantomjs"),o(q,"category","automation"),o(q,"weight",1),o(q,"description","Detects PhantomJS automation artifacts");var tt={WebDriverSignal:E,HeadlessSignal:C,NavigatorAnomalySignal:R,PermissionsSignal:D,MouseMovementSignal:y,KeyboardPatternSignal:M,InteractionTimingSignal:b,ScrollBehaviorSignal:T,PluginsSignal:S,WebGLSignal:L,CanvasSignal:P,AudioContextSignal:I,ScreenSignal:H,PageLoadSignal:A,DOMContentTimingSignal:O,PuppeteerSignal:B,PlaywrightSignal:V,SeleniumSignal:K,PhantomJSSignal:q},G=[new E,new C,new R,new D,new S,new L,new P,new I,new H,new A,new O,new B,new V,new K,new q],Q=[new y,new M,new b,new T],lt=[...G,...Q];function Z(g={}){let{includeInteractionSignals:e=!0,instantBotSignals:t=["webdriver","puppeteer","playwright","selenium","phantomjs"],...n}=g,i=e?[...G,...Q.map(s=>{let c=s.constructor;return new c(s.options)})]:G.map(s=>{let c=s.constructor;return new c(s.options)});return new j({signals:i,instantBotSignals:t,...n})}async function J(g={}){return Z({includeInteractionSignals:!g.skipInteractionSignals}).detect(g)}async function et(){return J({skipInteractionSignals:!0})}var ut={BotDetector:j,createDetector:Z,detect:J,detectInstant:et,Signal:m,Signals:tt,Verdict:z};return ht(dt);})();
1
+ var BotDetectorLib=(()=>{var $=Object.defineProperty;var nt=Object.getOwnPropertyDescriptor;var st=Object.getOwnPropertyNames;var ot=Object.prototype.hasOwnProperty;var at=(g,e,t)=>e in g?$(g,e,{enumerable:!0,configurable:!0,writable:!0,value:t}):g[e]=t;var rt=(g,e)=>{for(var t in e)$(g,t,{get:e[t],enumerable:!0})},ct=(g,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of st(e))!ot.call(g,i)&&i!==t&&$(g,i,{get:()=>e[i],enumerable:!(n=nt(e,i))||n.enumerable});return g};var ht=g=>ct($({},"__esModule",{value:!0}),g);var o=(g,e,t)=>at(g,typeof e!="symbol"?e+"":e,t);var dt={};rt(dt,{AudioContextSignal:()=>I,BotDetector:()=>W,CanvasSignal:()=>P,DOMContentTimingSignal:()=>O,HeadlessSignal:()=>C,InteractionTimingSignal:()=>b,KeyboardPatternSignal:()=>M,MouseMovementSignal:()=>y,NavigatorAnomalySignal:()=>R,PageLoadSignal:()=>A,PermissionsSignal:()=>D,PhantomJSSignal:()=>q,PlaywrightSignal:()=>V,PluginsSignal:()=>S,PuppeteerSignal:()=>B,ScoringEngine:()=>U,ScreenSignal:()=>H,ScrollBehaviorSignal:()=>T,SeleniumSignal:()=>K,Signal:()=>m,Signals:()=>tt,Verdict:()=>z,VerdictEngine:()=>N,WebDriverSignal:()=>E,WebGLSignal:()=>L,createDetector:()=>Z,default:()=>ut,defaultInstantSignals:()=>G,defaultInteractionSignals:()=>Q,defaultSignals:()=>lt,detect:()=>J,detectInstant:()=>et});var m=class{constructor(e={}){this.options=e,this._lastResult=null}get id(){return this.constructor.id}get category(){return this.constructor.category}get weight(){var e;return(e=this.options.weight)!=null?e:this.constructor.weight}get description(){return this.constructor.description}get requiresInteraction(){return this.constructor.requiresInteraction}get lastResult(){return this._lastResult}async detect(){throw new Error(`Signal.detect() must be implemented by ${this.constructor.name}`)}async run(){try{return this._lastResult=await this.detect(),this._lastResult}catch(e){return this._lastResult={triggered:!1,value:null,confidence:0,error:e.message},this._lastResult}}reset(){this._lastResult=null}createResult(e,t=null,n=1){return{triggered:!!e,value:t,confidence:Math.max(0,Math.min(1,n))}}};o(m,"id","base-signal"),o(m,"category","uncategorized"),o(m,"weight",.5),o(m,"description","Base signal class"),o(m,"requiresInteraction",!1);var U=class{constructor(e={}){this.weightOverrides=e.weightOverrides||{},this.maxScore=e.maxScore||100,this._results=new Map}getWeight(e,t){var n;return(n=this.weightOverrides[e])!=null?n:t}addResult(e,t,n){let i=this.getWeight(e,n);this._results.set(e,{...t,weight:i,contribution:t.triggered?i*t.confidence:0})}calculate(){if(this._results.size===0)return 0;let e=0,t=0;for(let[,i]of this._results)e+=i.weight,t+=i.contribution;if(e===0)return 0;let n=t/e*this.maxScore;return Math.round(n*100)/100}getBreakdown(){let e=[];for(let[t,n]of this._results)e.push({signalId:t,triggered:n.triggered,confidence:n.confidence,weight:n.weight,contribution:n.contribution,percentOfScore:this.calculate()>0?(n.contribution/this.calculate()*100).toFixed(1):"0.0"});return e.sort((t,n)=>n.contribution-t.contribution)}getTriggeredSignals(){let e=[];for(let[t,n]of this._results)n.triggered&&e.push(t);return e}getTriggeredCount(){let e=0;for(let[,t]of this._results)t.triggered&&e++;return e}reset(){this._results.clear()}};var z={HUMAN:"human",SUSPICIOUS:"suspicious",BOT:"bot"},F=class F{constructor(e={}){var t,n;this.humanThreshold=(t=e.humanThreshold)!=null?t:F.DEFAULT_THRESHOLDS.human,this.suspiciousThreshold=(n=e.suspiciousThreshold)!=null?n:F.DEFAULT_THRESHOLDS.suspicious,this.instantBotSignals=new Set(e.instantBotSignals||[])}getVerdict(e,t=[]){for(let c of t)if(this.instantBotSignals.has(c))return{verdict:z.BOT,score:e,confidence:"high",reason:`Instant bot signal triggered: ${c}`,triggeredCount:t.length};let n,i,s;return e<this.humanThreshold?(n=z.HUMAN,i=e<10?"high":"medium",s="Low bot score"):e<this.suspiciousThreshold?(n=z.SUSPICIOUS,i="medium",s="Moderate bot indicators detected"):(n=z.BOT,i=e>=75?"high":"medium",s="High accumulation of bot indicators"),{verdict:n,score:e,confidence:i,reason:s,triggeredCount:t.length}}isInstantBotSignal(e){return this.instantBotSignals.has(e)}addInstantBotSignal(e){this.instantBotSignals.add(e)}setThresholds(e){e.human!==void 0&&(this.humanThreshold=e.human),e.suspicious!==void 0&&(this.suspiciousThreshold=e.suspicious)}};o(F,"DEFAULT_THRESHOLDS",{human:20,suspicious:50});var N=F;var W=class g{constructor(e={}){if(this.options=e,this._signals=new Map,this._scoringEngine=new U({weightOverrides:e.weightOverrides}),this._verdictEngine=new N({humanThreshold:e.humanThreshold,suspiciousThreshold:e.suspiciousThreshold,instantBotSignals:e.instantBotSignals}),this._lastDetection=null,this._detectionTimeout=e.detectionTimeout||5e3,this._isRunning=!1,e.signals)for(let t of e.signals)this.registerSignal(t)}registerSignal(e){if(!(e instanceof m))throw new Error("Signal must be an instance of Signal class");let t=e.id;if(this._signals.has(t))throw new Error(`Signal with ID "${t}" is already registered`);return this._signals.set(t,e),this}registerSignals(e){for(let t of e)this.registerSignal(t);return this}unregisterSignal(e){return this._signals.delete(e)}getSignal(e){return this._signals.get(e)}getSignals(){return Array.from(this._signals.values())}getSignalsByCategory(e){return this.getSignals().filter(t=>t.category===e)}async detect(e={}){if(this._isRunning)throw new Error("Detection is already running");this._isRunning=!0,this._scoringEngine.reset();let t=performance.now(),n=new Map;try{let i=this.getSignals().filter(u=>!(e.skipInteractionSignals&&u.requiresInteraction)),s=i.map(async u=>{let l=await Promise.race([u.run(),new Promise(h=>setTimeout(()=>h({triggered:!1,value:null,confidence:0,error:"timeout"}),this._detectionTimeout))]);return{signal:u,result:l}}),c=await Promise.all(s);for(let{signal:u,result:l}of c)n.set(u.id,{...l,category:u.category,weight:u.weight,description:u.description}),this._scoringEngine.addResult(u.id,l,u.weight);let r=this._scoringEngine.calculate(),a=this._scoringEngine.getTriggeredSignals(),p=this._verdictEngine.getVerdict(r,a),d=performance.now()-t;return this._lastDetection={...p,signals:Object.fromEntries(n),breakdown:this._scoringEngine.getBreakdown(),timestamp:Date.now(),detectionTimeMs:Math.round(d),totalSignals:i.length,triggeredSignals:a},this._lastDetection}finally{this._isRunning=!1}}getLastDetection(){return this._lastDetection}getScore(){var e,t;return(t=(e=this._lastDetection)==null?void 0:e.score)!=null?t:0}getTriggeredSignals(){var e,t;return(t=(e=this._lastDetection)==null?void 0:e.triggeredSignals)!=null?t:[]}isRunning(){return this._isRunning}reset(){this._scoringEngine.reset(),this._lastDetection=null;for(let e of this._signals.values())e.reset()}configure(e){(e.humanThreshold!==void 0||e.suspiciousThreshold!==void 0)&&this._verdictEngine.setThresholds({human:e.humanThreshold,suspicious:e.suspiciousThreshold}),e.detectionTimeout!==void 0&&(this._detectionTimeout=e.detectionTimeout)}static withDefaults(e={}){return new g(e)}};var E=class extends m{async detect(){if(navigator.webdriver===!0)return this.createResult(!0,{webdriver:!0},1);let e=Object.getOwnPropertyDescriptor(navigator,"webdriver");if(e&&(e.get||!e.configurable))return this.createResult(!0,{webdriver:"modified",descriptor:{configurable:e.configurable,enumerable:e.enumerable,hasGetter:!!e.get}},.8);try{let t=Object.getPrototypeOf(navigator),n=Object.getOwnPropertyDescriptor(t,"webdriver");if(n&&n.get&&n.get.call(navigator)===!0)return this.createResult(!0,{webdriver:!0,source:"prototype"},1)}catch{}return this.createResult(!1)}};o(E,"id","webdriver"),o(E,"category","environment"),o(E,"weight",1),o(E,"description","Detects navigator.webdriver automation flag");var C=class extends m{async detect(){let e=[],t=0,n=navigator.userAgent||"";n.includes("HeadlessChrome")&&(e.push("headless-ua"),t=Math.max(t,1)),n.includes("Chrome")&&!n.includes("Chromium")&&(typeof window.chrome>"u"?(e.push("missing-chrome-object"),t=Math.max(t,.6)):window.chrome.runtime||(e.push("missing-chrome-runtime"),t=Math.max(t,.4))),navigator.plugins&&navigator.plugins.length===0&&(e.push("no-plugins"),t=Math.max(t,.5)),(!navigator.languages||navigator.languages.length===0)&&(e.push("no-languages"),t=Math.max(t,.6)),window.outerWidth===0&&window.outerHeight===0&&(e.push("zero-outer-dimensions"),t=Math.max(t,.7)),typeof navigator.connection>"u"&&n.includes("Chrome")&&(e.push("missing-connection-api"),t=Math.max(t,.3));try{typeof Notification<"u"&&Notification.permission==="denied"&&window.outerWidth===0&&(e.push("notification-headless-pattern"),t=Math.max(t,.5))}catch{}(window.callPhantom||window._phantom)&&(e.push("phantomjs"),t=Math.max(t,1)),window.__nightmare&&(e.push("nightmare"),t=Math.max(t,1));let i=e.length>0;return e.length>=3&&(t=Math.min(1,t+.2)),this.createResult(i,{indicators:e},t)}};o(C,"id","headless"),o(C,"category","environment"),o(C,"weight",.8),o(C,"description","Detects headless browser indicators");var R=class extends m{async detect(){let e=[],t=0,n=0,i=navigator.userAgent||"",s=navigator.platform||"";n++,s.includes("Win")&&!i.includes("Windows")?(e.push("platform-ua-mismatch-windows"),t+=1):s.includes("Mac")&&!i.includes("Mac")?(e.push("platform-ua-mismatch-mac"),t+=1):s.includes("Linux")&&!i.includes("Linux")&&!i.includes("Android")&&(e.push("platform-ua-mismatch-linux"),t+=1),n++,(!s||s===""||s==="undefined")&&(e.push("empty-platform"),t+=1),n++,navigator.language&&navigator.languages&&(navigator.languages.includes(navigator.language)||(e.push("language-mismatch"),t+=.5)),n++,i.includes("Chrome")&&navigator.vendor!=="Google Inc."?(e.push("vendor-mismatch-chrome"),t+=.5):i.includes("Firefox")&&navigator.vendor!==""?(e.push("vendor-mismatch-firefox"),t+=.5):i.includes("Safari")&&!i.includes("Chrome")&&navigator.vendor!=="Apple Computer, Inc."&&(e.push("vendor-mismatch-safari"),t+=.5),n++,typeof navigator.hardwareConcurrency<"u"&&(navigator.hardwareConcurrency===0||navigator.hardwareConcurrency>128)&&(e.push("suspicious-hardware-concurrency"),t+=.5),n++,typeof navigator.deviceMemory<"u"&&(navigator.deviceMemory===0||navigator.deviceMemory>512)&&(e.push("suspicious-device-memory"),t+=.5),n++;let c=/Android|iPhone|iPad|iPod|Mobile/i.test(i),r=navigator.maxTouchPoints>0;!c&&navigator.maxTouchPoints>5&&(e.push("desktop-high-touch-points"),t+=.3),n++;try{let d=Object.getOwnPropertyDescriptor(Navigator.prototype,"userAgent");d&&d.get&&d.get.toString().includes("native code")===!1&&(e.push("spoofed-user-agent"),t+=1)}catch{}let a=e.length>0,p=Math.min(1,t/Math.max(1,n));return this.createResult(a,{anomalies:e},p)}};o(R,"id","navigator-anomaly"),o(R,"category","environment"),o(R,"weight",.7),o(R,"description","Detects navigator property inconsistencies");var D=class extends m{async detect(){let e=[];if(!navigator.permissions)return this.createResult(!1,{supported:!1},0);try{let i=await navigator.permissions.query({name:"notifications"});if(typeof Notification<"u"){let s=Notification.permission;(s==="granted"&&i.state!=="granted"||s==="denied"&&i.state!=="denied"||s==="default"&&i.state!=="prompt")&&e.push("notification-permission-mismatch")}try{(await navigator.permissions.query({name:"geolocation"})).state==="denied"&&window.outerWidth===0&&e.push("geo-denied-headless")}catch{}try{await navigator.permissions.query({name:"camera"})}catch(s){s.name==="TypeError"&&e.push("camera-permission-error")}}catch(i){i.name!=="TypeError"&&e.push("permissions-query-error")}let t=e.length>0,n=Math.min(1,e.length*.4);return this.createResult(t,{anomalies:e},n)}};o(D,"id","permissions"),o(D,"category","environment"),o(D,"weight",.5),o(D,"description","Detects Permissions API anomalies");var y=class extends m{constructor(e={}){super(e),this._movements=[],this._isTracking=!1,this._trackingDuration=e.trackingDuration||3e3,this._minMovements=e.minMovements||5,this._boundHandler=null}startTracking(){this._isTracking||(this._movements=[],this._isTracking=!0,this._boundHandler=e=>{this._movements.push({x:e.clientX,y:e.clientY,t:performance.now()})},document.addEventListener("mousemove",this._boundHandler,{passive:!0}))}stopTracking(){this._isTracking&&(this._isTracking=!1,this._boundHandler&&(document.removeEventListener("mousemove",this._boundHandler),this._boundHandler=null))}async detect(){let e=[],t=0;this._movements.length===0&&(this.startTracking(),await new Promise(c=>setTimeout(c,this._trackingDuration)),this.stopTracking());let n=this._movements;if(n.length<this._minMovements)return e.push("no-mouse-movement"),t=Math.max(t,.6),this.createResult(!0,{anomalies:e,movements:n.length},t);let i=this._analyzeMovements(n);i.teleportCount>0&&(e.push("mouse-teleportation"),t=Math.max(t,.7)),i.linearPathRatio>.9&&(e.push("linear-path"),t=Math.max(t,.8)),i.velocityVariance<.01&&n.length>10&&(e.push("constant-velocity"),t=Math.max(t,.7)),i.accelerationChanges===0&&n.length>10&&(e.push("no-acceleration-variance"),t=Math.max(t,.6)),i.timingVariance<1&&n.length>10&&(e.push("robotic-timing"),t=Math.max(t,.8));let s=e.length>0;return this.createResult(s,{anomalies:e,movementCount:n.length,analysis:i},t)}_analyzeMovements(e){if(e.length<3)return{teleportCount:0,linearPathRatio:0,velocityVariance:0,accelerationChanges:0,timingVariance:0};let t=0,n=[],i=[],s=[];for(let l=1;l<e.length;l++){let h=e[l-1],f=e[l],x=f.x-h.x,_=f.y-h.y,w=f.t-h.t;if(w===0)continue;let k=Math.sqrt(x*x+_*_),v=k/w;n.push(v),i.push(Math.atan2(_,x)),s.push(w),k>300&&w<10&&t++}let c=n.reduce((l,h)=>l+h,0)/n.length,r=n.reduce((l,h)=>l+Math.pow(h-c,2),0)/n.length,a=0;if(i.length>1){let l=0;for(let h=1;h<i.length;h++)Math.abs(i[h]-i[h-1])<.1&&l++;a=l/(i.length-1)}let p=s.reduce((l,h)=>l+h,0)/s.length,d=s.reduce((l,h)=>l+Math.pow(h-p,2),0)/s.length,u=0;for(let l=1;l<n.length;l++)(n[l]-n[l-1])*(n[l-1]-(n[l-2]||0))<0&&u++;return{teleportCount:t,linearPathRatio:a,velocityVariance:r,accelerationChanges:u,timingVariance:d}}reset(){super.reset(),this.stopTracking(),this._movements=[]}};o(y,"id","mouse-movement"),o(y,"category","behavior"),o(y,"weight",.9),o(y,"description","Detects non-human mouse movement patterns"),o(y,"requiresInteraction",!0);var M=class extends m{constructor(e={}){super(e),this._keystrokes=[],this._isTracking=!1,this._trackingDuration=e.trackingDuration||5e3,this._minKeystrokes=e.minKeystrokes||10,this._boundKeydownHandler=null,this._boundKeyupHandler=null}startTracking(){this._isTracking||(this._keystrokes=[],this._isTracking=!0,this._boundKeydownHandler=e=>{this._keystrokes.push({type:"down",key:e.key,code:e.code,t:performance.now()})},this._boundKeyupHandler=e=>{this._keystrokes.push({type:"up",key:e.key,code:e.code,t:performance.now()})},document.addEventListener("keydown",this._boundKeydownHandler,{passive:!0}),document.addEventListener("keyup",this._boundKeyupHandler,{passive:!0}))}stopTracking(){this._isTracking&&(this._isTracking=!1,this._boundKeydownHandler&&(document.removeEventListener("keydown",this._boundKeydownHandler),this._boundKeydownHandler=null),this._boundKeyupHandler&&(document.removeEventListener("keyup",this._boundKeyupHandler),this._boundKeyupHandler=null))}async detect(){let e=[],t=0;this._keystrokes.length===0&&(this.startTracking(),await new Promise(r=>setTimeout(r,this._trackingDuration)),this.stopTracking());let n=this._keystrokes,i=n.filter(r=>r.type==="down");if(i.length<this._minKeystrokes)return this.createResult(!1,{reason:"insufficient-data",keystrokes:i.length},0);let s=this._analyzeKeystrokes(n);s.avgInterKeystrokeTime<50&&i.length>20&&(e.push("inhuman-speed"),t=Math.max(t,.9)),s.timingVariance<5&&i.length>15&&(e.push("robotic-timing"),t=Math.max(t,.8)),s.missingKeyups>i.length*.5&&(e.push("missing-keyups"),t=Math.max(t,.7)),s.holdTimeVariance<2&&s.holdTimes.length>10&&(e.push("constant-hold-time"),t=Math.max(t,.6)),s.sequentialKeys>i.length*.8&&i.length>10&&(e.push("sequential-input"),t=Math.max(t,.5)),s.rhythmScore<.1&&i.length>20&&(e.push("no-rhythm-variation"),t=Math.max(t,.6));let c=e.length>0;return this.createResult(c,{anomalies:e,keystrokeCount:i.length,analysis:s},t)}_analyzeKeystrokes(e){let t=e.filter(h=>h.type==="down"),n=e.filter(h=>h.type==="up");if(t.length<2)return{avgInterKeystrokeTime:1/0,timingVariance:1/0,missingKeyups:0,holdTimeVariance:1/0,holdTimes:[],sequentialKeys:0,rhythmScore:1};let i=[];for(let h=1;h<t.length;h++)i.push(t[h].t-t[h-1].t);let s=i.reduce((h,f)=>h+f,0)/i.length,c=i.reduce((h,f)=>h+Math.pow(f-s,2),0)/i.length,r=[];for(let h of t){let f=n.find(x=>x.key===h.key&&x.t>h.t);f&&r.push(f.t-h.t)}let a=r.length>0?r.reduce((h,f)=>h+f,0)/r.length:0,p=r.length>0?r.reduce((h,f)=>h+Math.pow(f-a,2),0)/r.length:1/0,d=t.length-r.length,u=0;for(let h=1;h<t.length;h++){let f=t[h-1].key.charCodeAt(0),x=t[h].key.charCodeAt(0);Math.abs(x-f)===1&&u++}let l=0;if(i.length>5){let h=[...i].sort((_,w)=>_-w),f=h[Math.floor(h.length/2)];l=i.filter(_=>Math.abs(_-f)>f*.3).length/i.length}return{avgInterKeystrokeTime:s,timingVariance:c,missingKeyups:d,holdTimeVariance:p,holdTimes:r,sequentialKeys:u,rhythmScore:l}}reset(){super.reset(),this.stopTracking(),this._keystrokes=[]}};o(M,"id","keyboard-pattern"),o(M,"category","behavior"),o(M,"weight",.8),o(M,"description","Detects non-human keystroke patterns"),o(M,"requiresInteraction",!0);var b=class extends m{constructor(e={}){super(e),this._pageLoadTime=performance.now(),this._firstInteractionTime=null,this._interactions=[],this._isTracking=!1,this._trackingDuration=e.trackingDuration||5e3,this._boundHandler=null}startTracking(){if(this._isTracking)return;this._interactions=[],this._isTracking=!0;let e=["click","mousedown","touchstart","keydown","scroll"];this._boundHandler=t=>{let n=performance.now();this._firstInteractionTime===null&&(this._firstInteractionTime=n),this._interactions.push({type:t.type,t:n,timeSinceLoad:n-this._pageLoadTime})};for(let t of e)document.addEventListener(t,this._boundHandler,{passive:!0,capture:!0})}stopTracking(){if(!this._isTracking)return;this._isTracking=!1;let e=["click","mousedown","touchstart","keydown","scroll"];if(this._boundHandler){for(let t of e)document.removeEventListener(t,this._boundHandler,{capture:!0});this._boundHandler=null}}async detect(){let e=[],t=0;!this._isTracking&&this._interactions.length===0&&(this.startTracking(),await new Promise(r=>setTimeout(r,this._trackingDuration)),this.stopTracking());let n=this._interactions;if(n.length===0)return this.createResult(!1,{reason:"no-interactions"},0);let i=n[0];if(i.timeSinceLoad<100?(e.push("instant-interaction"),t=Math.max(t,.9)):i.timeSinceLoad<300&&(e.push("very-fast-interaction"),t=Math.max(t,.6)),n.length>3){let r=[];for(let l=1;l<n.length;l++)r.push(n[l].t-n[l-1].t);let a=r.reduce((l,h)=>l+h,0)/r.length;r.reduce((l,h)=>l+Math.pow(h-a,2),0)/r.length<10&&n.length>5&&(e.push("robotic-intervals"),t=Math.max(t,.8));let d=50,u=0;for(let l of r)l<d&&u++;u>r.length*.7&&(e.push("burst-interactions"),t=Math.max(t,.7))}let s=n.map(r=>r.type).join(",");if(n.length>=6){let r=Math.floor(n.length/2),a=n.slice(0,r).map(d=>d.type).join(","),p=n.slice(r,r*2).map(d=>d.type).join(",");a===p&&a.length>0&&(e.push("repeated-sequence"),t=Math.max(t,.6))}let c=e.length>0;return this.createResult(c,{anomalies:e,interactionCount:n.length,timeToFirstInteraction:i.timeSinceLoad,firstInteractionType:i.type},t)}reset(){super.reset(),this.stopTracking(),this._pageLoadTime=performance.now(),this._firstInteractionTime=null,this._interactions=[]}};o(b,"id","interaction-timing"),o(b,"category","behavior"),o(b,"weight",.6),o(b,"description","Detects suspicious interaction timing"),o(b,"requiresInteraction",!0);var T=class extends m{constructor(e={}){super(e),this._scrollEvents=[],this._isTracking=!1,this._trackingDuration=e.trackingDuration||3e3,this._boundHandler=null}startTracking(){this._isTracking||(this._scrollEvents=[],this._isTracking=!0,this._boundHandler=()=>{this._scrollEvents.push({scrollY:window.scrollY,scrollX:window.scrollX,t:performance.now()})},window.addEventListener("scroll",this._boundHandler,{passive:!0}))}stopTracking(){this._isTracking&&(this._isTracking=!1,this._boundHandler&&(window.removeEventListener("scroll",this._boundHandler),this._boundHandler=null))}async detect(){let e=[],t=0;this._scrollEvents.length===0&&(this.startTracking(),await new Promise(c=>setTimeout(c,this._trackingDuration)),this.stopTracking());let n=this._scrollEvents;if(n.length<3)return this.createResult(!1,{reason:"insufficient-scroll-data",scrollEvents:n.length},0);let i=this._analyzeScrollPatterns(n);i.instantJumps>0&&(e.push("instant-scroll-jumps"),t=Math.max(t,.7)),i.velocityVariance<.1&&n.length>10&&(e.push("constant-scroll-velocity"),t=Math.max(t,.6)),i.momentumEvents===0&&n.length>5&&(e.push("no-scroll-momentum"),t=Math.max(t,.5)),i.intervalVariance<5&&n.length>10&&(e.push("robotic-scroll-timing"),t=Math.max(t,.7)),i.scrollDirections===1&&Math.abs(i.totalScrollY)>1e3&&i.velocityVariance<1&&(e.push("one-dimensional-scroll"),t=Math.max(t,.4)),i.exactPositionScrolls>2&&(e.push("exact-position-scrolls"),t=Math.max(t,.6));let s=e.length>0;return this.createResult(s,{anomalies:e,scrollEventCount:n.length,analysis:i},t)}_analyzeScrollPatterns(e){if(e.length<2)return{instantJumps:0,velocityVariance:0,momentumEvents:0,intervalVariance:0,scrollDirections:0,totalScrollY:0,exactPositionScrolls:0};let t=0,n=0,i=[],s=[],c=!1,r=!1,a=0,p=[0,100,200,300,400,500,600,800,1e3];for(let _=1;_<e.length;_++){let w=e[_-1],k=e[_],v=k.scrollY-w.scrollY,j=k.scrollX-w.scrollX,Y=k.t-w.t;if(s.push(Y),Math.abs(v)>0&&(c=!0),Math.abs(j)>0&&(r=!0),Y===0)continue;let X=Math.sqrt(v*v+j*j)/Y;if(i.push(X),Math.abs(v)+Math.abs(j)>200&&Y<20&&t++,_>1&&i.length>1){let it=i[i.length-2];X<it*.9&&X>0&&n++}p.includes(Math.round(k.scrollY))&&a++}let d=i.length>0?i.reduce((_,w)=>_+w,0)/i.length:0,u=i.length>0?i.reduce((_,w)=>_+Math.pow(w-d,2),0)/i.length:0,l=s.reduce((_,w)=>_+w,0)/s.length,h=s.reduce((_,w)=>_+Math.pow(w-l,2),0)/s.length,f=0;c&&f++,r&&f++;let x=e[e.length-1].scrollY-e[0].scrollY;return{instantJumps:t,velocityVariance:u,momentumEvents:n,intervalVariance:h,scrollDirections:f,totalScrollY:x,exactPositionScrolls:a}}reset(){super.reset(),this.stopTracking(),this._scrollEvents=[]}};o(T,"id","scroll-behavior"),o(T,"category","behavior"),o(T,"weight",.5),o(T,"description","Detects programmatic scroll patterns"),o(T,"requiresInteraction",!0);var S=class extends m{async detect(){let e=[],t=0,n=navigator.plugins,i=navigator.mimeTypes;if(!n)return e.push("no-plugins-object"),t=Math.max(t,.6),this.createResult(!0,{anomalies:e},t);n.length===0&&(e.push("empty-plugins"),t=Math.max(t,.5));let s=navigator.userAgent||"";if(s.includes("Chrome")&&!s.includes("Chromium")&&!Array.from(n).some(p=>p.name.includes("PDF")||p.name.includes("Chromium PDF"))&&n.length===0&&(e.push("chrome-missing-pdf-plugin"),t=Math.max(t,.4)),n.length>0&&i){let a=0;for(let p=0;p<n.length;p++)a+=n[p].length||0;i.length===0&&a>0&&(e.push("mimetypes-mismatch"),t=Math.max(t,.5))}if(n.length>1){let a=Array.from(n).map(d=>d.name);new Set(a).size<a.length&&(e.push("duplicate-plugins"),t=Math.max(t,.6))}try{let a=Object.getOwnPropertyDescriptor(Navigator.prototype,"plugins");a&&a.get&&(a.get.toString().includes("[native code]")||(e.push("plugins-getter-overridden"),t=Math.max(t,.7)))}catch{}!/Android|iPhone|iPad|iPod|Mobile/i.test(s)&&n.length===1&&(e.push("minimal-plugins"),t=Math.max(t,.3));let r=e.length>0;return this.createResult(r,{anomalies:e,pluginCount:n.length,mimeTypeCount:(i==null?void 0:i.length)||0},t)}};o(S,"id","plugins"),o(S,"category","fingerprint"),o(S,"weight",.6),o(S,"description","Detects browser plugin anomalies");var L=class extends m{async detect(){let e=[],t=0,n=document.createElement("canvas"),i=null;try{i=n.getContext("webgl")||n.getContext("experimental-webgl")}catch{e.push("webgl-error"),t=Math.max(t,.5)}if(!i)return e.push("webgl-unavailable"),t=Math.max(t,.4),this.createResult(!0,{anomalies:e},t);let s=i.getExtension("WEBGL_debug_renderer_info"),c="",r="";s&&(c=i.getParameter(s.UNMASKED_VENDOR_WEBGL)||"",r=i.getParameter(s.UNMASKED_RENDERER_WEBGL)||""),!c&&!r&&(e.push("no-webgl-renderer-info"),t=Math.max(t,.6));let a=["swiftshader","llvmpipe","software","mesa","google swiftshader","vmware","virtualbox"],p=r.toLowerCase();for(let x of a)if(p.includes(x)){e.push(`suspicious-renderer-${x.replace(/\s+/g,"-")}`),t=Math.max(t,.7);break}c&&r&&(p.includes("nvidia")&&!c.toLowerCase().includes("nvidia")&&(e.push("vendor-renderer-mismatch"),t=Math.max(t,.6)),(p.includes("amd")||p.includes("radeon"))&&!c.toLowerCase().includes("amd")&&!c.toLowerCase().includes("ati")&&(e.push("vendor-renderer-mismatch"),t=Math.max(t,.6)));let d=i.getSupportedExtensions()||[];d.length<5&&(e.push("few-webgl-extensions"),t=Math.max(t,.4));let u=i.getParameter(i.MAX_TEXTURE_SIZE),l=i.getParameter(i.MAX_VIEWPORT_DIMS);(u<1024||u>65536)&&(e.push("unrealistic-max-texture"),t=Math.max(t,.5));try{i.clearColor(0,0,0,1),i.clear(i.COLOR_BUFFER_BIT);let x=new Uint8Array(4);i.readPixels(0,0,1,1,i.RGBA,i.UNSIGNED_BYTE,x),x[3]!==255&&(e.push("webgl-render-failure"),t=Math.max(t,.6))}catch{e.push("webgl-render-error"),t=Math.max(t,.5)}let h=i.getExtension("WEBGL_lose_context");h&&h.loseContext();let f=e.length>0;return this.createResult(f,{anomalies:e,vendor:c,renderer:r,extensionCount:d.length,maxTextureSize:u},t)}};o(L,"id","webgl"),o(L,"category","fingerprint"),o(L,"weight",.7),o(L,"description","Detects WebGL rendering anomalies");var P=class extends m{async detect(){let e=[],t=0;try{let i=document.createElement("canvas");i.width=200,i.height=50;let s=i.getContext("2d");if(!s)return e.push("canvas-context-unavailable"),t=Math.max(t,.5),this.createResult(!0,{anomalies:e},t);s.textBaseline="alphabetic",s.font="14px Arial",s.fillStyle="#f60",s.fillRect(0,0,200,50),s.fillStyle="#069",s.fillText("Bot Detection Test \u{1F916}",2,15),s.fillStyle="rgba(102, 204, 0, 0.7)",s.fillText("Canvas Fingerprint",4,30),s.beginPath(),s.arc(100,25,10,0,Math.PI*2,!0),s.closePath(),s.fill();let c=i.toDataURL();s.clearRect(0,0,200,50),s.fillStyle="#f60",s.fillRect(0,0,200,50),s.fillStyle="#069",s.fillText("Bot Detection Test \u{1F916}",2,15),s.fillStyle="rgba(102, 204, 0, 0.7)",s.fillText("Canvas Fingerprint",4,30),s.beginPath(),s.arc(100,25,10,0,Math.PI*2,!0),s.closePath(),s.fill();let r=i.toDataURL();c!==r&&(e.push("canvas-randomized"),t=Math.max(t,.6)),c.length<1e3&&(e.push("canvas-possibly-blank"),t=Math.max(t,.4));let a=document.createElement("canvas");a.width=200,a.height=50;let p=a.toDataURL();c===p&&(e.push("canvas-rendering-blocked"),t=Math.max(t,.7));try{i.toDataURL.toString().includes("[native code]")||(e.push("toDataURL-overridden"),t=Math.max(t,.8))}catch{}let u=s.getImageData(0,0,200,50).data,l=!0,h=[u[0],u[1],u[2],u[3]];for(let f=4;f<u.length;f+=4)if(u[f]!==h[0]||u[f+1]!==h[1]||u[f+2]!==h[2]){l=!1;break}l&&(e.push("uniform-pixel-data"),t=Math.max(t,.6))}catch{e.push("canvas-error"),t=Math.max(t,.4)}let n=e.length>0;return this.createResult(n,{anomalies:e},t)}};o(P,"id","canvas"),o(P,"category","fingerprint"),o(P,"weight",.5),o(P,"description","Detects canvas fingerprint anomalies");var I=class extends m{async detect(){let e=[],t=0,n=window.AudioContext||window.webkitAudioContext;if(!n)return e.push("audio-context-unavailable"),t=Math.max(t,.4),this.createResult(!0,{anomalies:e},t);let i=null,s=null,c=null;try{i=new n;let a=i.sampleRate;if(a!==44100&&a!==48e3&&a!==96e3&&(e.push("unusual-sample-rate"),t=Math.max(t,.3)),s=i.createOscillator(),c=i.createAnalyser(),!s||!c)e.push("audio-nodes-unavailable"),t=Math.max(t,.5);else{let d=c.fftSize,u=i.destination;(!u||u.maxChannelCount===0)&&(e.push("no-audio-destination"),t=Math.max(t,.6)),u&&u.maxChannelCount<2&&(e.push("mono-audio-only"),t=Math.max(t,.3))}try{n.toString().includes("[native code]")||(e.push("audio-context-overridden"),t=Math.max(t,.7))}catch{}try{if(i.state==="suspended"&&await i.resume().catch(()=>{}),i.state==="running"){let d=i.createOscillator(),u=i.createGain(),l=i.createScriptProcessor?i.createScriptProcessor(4096,1,1):null;l&&(d.type="triangle",d.frequency.value=1e4,u.gain.value=0,d.connect(u),u.connect(l),l.connect(i.destination),d.start(0),await new Promise(h=>setTimeout(h,50)),d.stop(),d.disconnect(),u.disconnect(),l.disconnect())}}catch{e.push("audio-fingerprint-blocked"),t=Math.max(t,.4)}window.OfflineAudioContext||window.webkitOfflineAudioContext||(e.push("offline-audio-context-unavailable"),t=Math.max(t,.3))}catch{e.push("audio-context-error"),t=Math.max(t,.4)}finally{if(s)try{s.disconnect()}catch{}if(c)try{c.disconnect()}catch{}if(i)try{i.close()}catch{}}let r=e.length>0;return this.createResult(r,{anomalies:e},t)}};o(I,"id","audio-context"),o(I,"category","fingerprint"),o(I,"weight",.5),o(I,"description","Detects AudioContext anomalies");var H=class extends m{async detect(){let e=[],t=0,n=window.screen;if(!n)return e.push("no-screen-object"),t=Math.max(t,.6),this.createResult(!0,{anomalies:e},t);let i=n.width,s=n.height,c=n.availWidth,r=n.availHeight,a=n.colorDepth,p=n.pixelDepth,d=window.outerWidth,u=window.outerHeight,l=window.innerWidth,h=window.innerHeight;(d===0||u===0)&&(e.push("zero-outer-dimensions"),t=Math.max(t,.8)),(l===0||h===0)&&(e.push("zero-inner-dimensions"),t=Math.max(t,.7));let f=navigator.userAgent||"";!/Android|iPhone|iPad|iPod|Mobile/i.test(f)&&(i<640||s<480)&&(e.push("very-small-screen"),t=Math.max(t,.5)),(i>7680||s>4320)&&(e.push("unrealistic-screen-size"),t=Math.max(t,.4));let _=[{w:800,h:600},{w:1024,h:768},{w:1920,h:1080}];for(let v of _)if(i===v.w&&s===v.h&&d===v.w&&u===v.h){e.push("headless-default-dimensions"),t=Math.max(t,.5);break}(c>i||r>s)&&(e.push("available-exceeds-total"),t=Math.max(t,.7)),(d>i||u>s)&&(e.push("window-exceeds-screen"),t=Math.max(t,.6)),a!==24&&a!==32&&a!==30&&a!==48&&(e.push("unusual-color-depth"),t=Math.max(t,.3)),a!==p&&(e.push("depth-mismatch"),t=Math.max(t,.3));let w=window.devicePixelRatio;if(w===0||w===void 0?(e.push("missing-device-pixel-ratio"),t=Math.max(t,.5)):(w<.5||w>5)&&(e.push("unusual-device-pixel-ratio"),t=Math.max(t,.4)),n.orientation){let v=n.orientation.type,j=n.orientation.angle;v.includes("landscape")&&i<s&&(e.push("orientation-dimension-mismatch"),t=Math.max(t,.4)),v.includes("portrait")&&i>s&&(e.push("orientation-dimension-mismatch"),t=Math.max(t,.4))}l===d&&h===u&&d>0&&u>0&&(e.push("no-browser-chrome"),t=Math.max(t,.5));let k=e.length>0;return this.createResult(k,{anomalies:e,dimensions:{screen:{width:i,height:s},available:{width:c,height:r},window:{outer:{width:d,height:u},inner:{width:l,height:h}},colorDepth:a,devicePixelRatio:w}},t)}};o(H,"id","screen"),o(H,"category","fingerprint"),o(H,"weight",.4),o(H,"description","Detects unusual screen dimensions");var A=class extends m{async detect(){let e=[],t=0;if(!window.performance||!performance.timing){if(performance.getEntriesByType){let v=performance.getEntriesByType("navigation");if(v.length>0)return this._analyzeNavigationTiming(v[0])}return e.push("no-performance-api"),t=Math.max(t,.3),this.createResult(!0,{anomalies:e},t)}let n=performance.timing,i=n.navigationStart,s=n.domContentLoadedEventEnd-i,c=n.domComplete-i,r=n.loadEventEnd-i,a=n.domainLookupEnd-n.domainLookupStart,p=n.connectEnd-n.connectStart,d=n.responseEnd-n.requestStart,u=n.domComplete-n.domLoading;s>0&&s<10&&(e.push("instant-dom-content-loaded"),t=Math.max(t,.7)),a===0&&p===0&&d<5&&(e.push("zero-network-timing"),t=Math.max(t,.4)),(s<0||c<0||r<0)&&(e.push("negative-timing"),t=Math.max(t,.8)),n.domContentLoadedEventEnd>0&&n.loadEventEnd>0&&n.domContentLoadedEventEnd>n.loadEventEnd&&(e.push("timing-order-violation"),t=Math.max(t,.7)),u>3e4&&(e.push("excessive-dom-processing"),t=Math.max(t,.3));let l=n.domContentLoadedEventStart-n.responseEnd;l>0&&l<5&&(e.push("instant-script-execution"),t=Math.max(t,.4));let h=performance.now(),f=performance.now();h===f&&h>0&&(e.push("frozen-performance-now"),t=Math.max(t,.6));let x=Date.now(),_=performance.now(),w=Date.now();Math.abs(w-x-(performance.now()-_))>100&&(e.push("timing-inconsistency"),t=Math.max(t,.5));let k=e.length>0;return this.createResult(k,{anomalies:e,timings:{domContentLoaded:s,domComplete:c,loadComplete:r,dnsLookup:a,tcpConnection:p,serverResponse:d,domProcessing:u}},t)}_analyzeNavigationTiming(e){let t=[],n=0,i=e.domContentLoadedEventEnd,s=e.loadEventEnd,c=e.domainLookupEnd-e.domainLookupStart,r=e.responseEnd-e.requestStart;i>0&&i<10&&(t.push("instant-dom-content-loaded"),n=Math.max(n,.7)),c===0&&r===0&&(t.push("zero-network-timing"),n=Math.max(n,.4));let a=t.length>0;return this.createResult(a,{anomalies:t,timings:{domContentLoaded:i,loadComplete:s,dnsLookup:c,serverResponse:r}},n)}};o(A,"id","page-load"),o(A,"category","timing"),o(A,"weight",.5),o(A,"description","Detects suspicious page load timing");var O=class extends m{constructor(e={}){super(e),this._domContentLoadedTime=null,this._documentReadyState=document.readyState,this._captureTime=performance.now(),document.readyState==="loading"&&document.addEventListener("DOMContentLoaded",()=>{this._domContentLoadedTime=performance.now()})}async detect(){let e=[],t=0,n=performance.now(),i=document.readyState,s=0,c=0,r=0;if(performance.getEntriesByType){let p=performance.getEntriesByType("resource");s=p.length;for(let d of p)c+=d.duration,d.initiatorType==="script"&&d.name.startsWith("http")&&r++}s===0&&i==="complete"&&(e.push("no-resources-loaded"),t=Math.max(t,.4)),this._domContentLoadedTime&&this._domContentLoadedTime<50&&s===0&&(e.push("instant-ready-no-resources"),t=Math.max(t,.6)),document.hidden&&this._documentReadyState==="loading"&&(e.push("hidden-at-load"),t=Math.max(t,.3)),typeof document.visibilityState>"u"&&(e.push("no-visibility-api"),t=Math.max(t,.4));try{let p=performance.now(),d=document.createElement("div");d.id="__bot_detection_test__",document.body.appendChild(d);let u=performance.now();document.body.removeChild(d);let l=performance.now(),h=u-p,f=l-u;h===0&&f===0&&(e.push("instant-dom-operations"),t=Math.max(t,.5))}catch{document.body||(e.push("no-document-body"),t=Math.max(t,.4))}if(typeof MutationObserver>"u"&&(e.push("no-mutation-observer"),t=Math.max(t,.5)),typeof requestAnimationFrame>"u"&&(e.push("no-request-animation-frame"),t=Math.max(t,.5)),performance.getEntriesByType){let p=performance.getEntriesByType("paint");!p.find(l=>l.name==="first-paint")&&i==="complete"&&n>1e3&&(e.push("no-first-paint"),t=Math.max(t,.4)),!p.find(l=>l.name==="first-contentful-paint")&&i==="complete"&&n>1e3&&(e.push("no-first-contentful-paint"),t=Math.max(t,.4))}typeof IntersectionObserver>"u"&&(e.push("no-intersection-observer"),t=Math.max(t,.4));let a=e.length>0;return this.createResult(a,{anomalies:e,metrics:{readyState:i,resourceCount:s,externalScriptCount:r,domContentLoadedTime:this._domContentLoadedTime,documentHidden:document.hidden}},t)}};o(O,"id","dom-content-timing"),o(O,"category","timing"),o(O,"weight",.4),o(O,"description","Analyzes DOM content loaded timing patterns");var B=class extends m{async detect(){let e=[],t=0;window.__puppeteer_evaluation_script__&&(e.push("puppeteer-evaluation-script"),t=Math.max(t,1));let n=["__puppeteer_evaluation_script__","__puppeteer","puppeteer"];for(let r of n)r in window&&(e.push(`global-${r}`),t=Math.max(t,1));(navigator.userAgent||"").includes("HeadlessChrome")&&(e.push("headless-chrome-ua"),t=Math.max(t,.9)),(window.cdc_adoQpoasnfa76pfcZLmcfl_Array||window.cdc_adoQpoasnfa76pfcZLmcfl_Promise||window.cdc_adoQpoasnfa76pfcZLmcfl_Symbol)&&(e.push("cdp-artifacts"),t=Math.max(t,1));try{window.eval.toString().includes("puppeteer")&&(e.push("eval-puppeteer"),t=Math.max(t,.9))}catch{}try{throw new Error("stack trace test")}catch(r){let a=r.stack||"";(a.includes("puppeteer")||a.includes("pptr"))&&(e.push("stack-trace-puppeteer"),t=Math.max(t,.8))}window.innerWidth===800&&window.innerHeight===600&&(e.push("default-viewport"),t=Math.max(t,.3)),navigator.webdriver===!0&&(e.push("webdriver-flag"),t=Math.max(t,.9)),Object.keys(window).filter(r=>r.startsWith("__")&&!r.startsWith("__zone_symbol__")&&typeof window[r]=="function").length>5&&(e.push("suspicious-bindings"),t=Math.max(t,.5)),typeof window.chrome<"u"&&(window.chrome.runtime||(e.push("incomplete-chrome-object"),t=Math.max(t,.4)));let c=e.length>0;return this.createResult(c,{indicators:e},t)}};o(B,"id","puppeteer"),o(B,"category","automation"),o(B,"weight",1),o(B,"description","Detects Puppeteer automation artifacts");var V=class extends m{async detect(){let e=[],t=0;window.__playwright&&(e.push("playwright-namespace"),t=Math.max(t,1));let n=["__playwright","__pw_manual","__pwInitScripts","playwright"];for(let c of n)c in window&&(e.push(`global-${c}`),t=Math.max(t,1));window.__playwright__binding__&&(e.push("playwright-binding"),t=Math.max(t,1));let i=navigator.userAgent||"";(i.includes("Playwright")||i.includes("HeadlessChrome"))&&(e.push("playwright-ua-marker"),t=Math.max(t,i.includes("Playwright")?1:.7)),navigator.webdriver===!0&&(e.push("webdriver-flag"),t=Math.max(t,.8));try{Object.keys(window).filter(a=>a.startsWith("__pw")).length>0&&(e.push("pw-bindings"),t=Math.max(t,1))}catch{}typeof window.__pw_date_intercepted<"u"&&(e.push("date-interception"),t=Math.max(t,.9)),window.__pw_geolocation__&&(e.push("geolocation-mock"),t=Math.max(t,.9)),window.__pw_permissions__&&(e.push("permissions-override"),t=Math.max(t,.9)),window.__cdpSession__&&(e.push("cdp-session"),t=Math.max(t,.8));try{throw new Error("stack trace test")}catch(c){let r=c.stack||"";(r.includes("playwright")||r.includes("__pw"))&&(e.push("stack-trace-playwright"),t=Math.max(t,.8))}try{let r=new Date().toLocaleString();window.__pwTimezone__&&(e.push("timezone-mock"),t=Math.max(t,.8))}catch{}let s=e.length>0;return this.createResult(s,{indicators:e},t)}};o(V,"id","playwright"),o(V,"category","automation"),o(V,"weight",1),o(V,"description","Detects Playwright automation artifacts");var K=class extends m{async detect(){let e=[],t=0;navigator.webdriver===!0&&(e.push("webdriver-flag"),t=Math.max(t,1));let n=["_selenium","callSelenium","_Selenium_IDE_Recorder","__selenium_evaluate","__selenium_unwrap","__webdriver_evaluate","__webdriver_unwrap","__webdriver_script_function","__webdriver_script_func","__fxdriver_evaluate","__fxdriver_unwrap","webdriver"];for(let a of n)a in window&&(e.push(`global-${a}`),t=Math.max(t,1));let i=["__webdriver_script_fn","__driver_evaluate","__webdriver_evaluate","__selenium_evaluate","__fxdriver_evaluate","__driver_unwrap","__webdriver_unwrap","__selenium_unwrap","__fxdriver_unwrap"];for(let a of i)a in document&&(e.push(`document-${a}`),t=Math.max(t,1));Object.keys(window).filter(a=>a.startsWith("$cdc_")||a.startsWith("$wdc_")||a.startsWith("$chrome_asyncScriptInfo")).length>0&&(e.push("chromedriver-variables"),t=Math.max(t,1)),(window.webdriverCallback||document.documentElement.getAttribute("webdriver"))&&(e.push("geckodriver-artifacts"),t=Math.max(t,1));try{let a=document.documentElement;(a.hasAttribute("webdriver")||a.getAttribute("selenium")||a.getAttribute("driver"))&&(e.push("document-webdriver-attr"),t=Math.max(t,1))}catch{}(window.selenium||window.sideex)&&(e.push("selenium-ide"),t=Math.max(t,1));try{let a=Object.getOwnPropertyDescriptor(Navigator.prototype,"webdriver");a&&a.get&&(a.get.toString().includes("[native code]")||(e.push("webdriver-getter-modified"),t=Math.max(t,.7)))}catch{}(window.domAutomation||window.domAutomationController)&&(e.push("dom-automation"),t=Math.max(t,1)),window.awesomium&&(e.push("awesomium"),t=Math.max(t,.9)),window.external&&window.external.toString().includes("Selenium")&&(e.push("external-selenium"),t=Math.max(t,1));let r=e.length>0;return this.createResult(r,{indicators:e},t)}};o(K,"id","selenium"),o(K,"category","automation"),o(K,"weight",1),o(K,"description","Detects Selenium WebDriver artifacts");var q=class extends m{async detect(){let e=[],t=0;window.callPhantom&&(e.push("callPhantom"),t=Math.max(t,1)),window._phantom&&(e.push("_phantom"),t=Math.max(t,1)),window.phantom&&(e.push("phantom"),t=Math.max(t,1));let n=navigator.userAgent||"";n.includes("PhantomJS")&&(e.push("phantomjs-ua"),t=Math.max(t,1)),window.__phantomas&&(e.push("phantomas"),t=Math.max(t,1)),window.__casper&&(e.push("casperjs"),t=Math.max(t,1)),window.casper&&(e.push("casper-global"),t=Math.max(t,1)),window.slimer&&(e.push("slimerjs"),t=Math.max(t,1)),window.__nightmare&&(e.push("nightmare"),t=Math.max(t,1)),window.nightmare&&(e.push("nightmare-global"),t=Math.max(t,1));try{let c=Function.prototype.toString.call(Function);(c.includes("phantom")||c.includes("Phantom"))&&(e.push("function-prototype-phantom"),t=Math.max(t,.8))}catch{}try{throw new Error("test")}catch(c){(c.stack||"").includes("phantom")&&(e.push("stack-trace-phantom"),t=Math.max(t,.9))}navigator.plugins&&navigator.plugins.length===0&&e.length>0&&(e.push("no-plugins-phantom"),t=Math.max(t,.5));let i=["__PHANTOM__","PHANTOM","Buffer","process"];for(let c of i)c in window&&c!=="Buffer"&&c!=="process"&&(e.push(`phantom-prop-${c.toLowerCase()}`),t=Math.max(t,.9));n.includes("QtWebKit")&&(e.push("qtwebkit"),t=Math.max(t,.7));let s=e.length>0;return this.createResult(s,{indicators:e},t)}};o(q,"id","phantomjs"),o(q,"category","automation"),o(q,"weight",1),o(q,"description","Detects PhantomJS automation artifacts");var tt={WebDriverSignal:E,HeadlessSignal:C,NavigatorAnomalySignal:R,PermissionsSignal:D,MouseMovementSignal:y,KeyboardPatternSignal:M,InteractionTimingSignal:b,ScrollBehaviorSignal:T,PluginsSignal:S,WebGLSignal:L,CanvasSignal:P,AudioContextSignal:I,ScreenSignal:H,PageLoadSignal:A,DOMContentTimingSignal:O,PuppeteerSignal:B,PlaywrightSignal:V,SeleniumSignal:K,PhantomJSSignal:q},G=[new E,new C,new R,new D,new S,new L,new P,new I,new H,new A,new O,new B,new V,new K,new q],Q=[new y,new M,new b,new T],lt=[...G,...Q];function Z(g={}){let{includeInteractionSignals:e=!0,instantBotSignals:t=["webdriver","puppeteer","playwright","selenium","phantomjs"],...n}=g,i=e?[...G,...Q.map(s=>{let c=s.constructor;return new c(s.options)})]:G.map(s=>{let c=s.constructor;return new c(s.options)});return new W({signals:i,instantBotSignals:t,...n})}async function J(g={}){return Z({includeInteractionSignals:!g.skipInteractionSignals}).detect(g)}async function et(){return J({skipInteractionSignals:!0})}var ut={BotDetector:W,createDetector:Z,detect:J,detectInstant:et,Signal:m,Signals:tt,Verdict:z};return ht(dt);})();
package/package.json CHANGED
@@ -1,19 +1,20 @@
1
1
  {
2
2
  "name": "@niksbanna/bot-detector",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Production-grade client-side bot detection system using signal-based scoring",
5
5
  "main": "dist/bot-detector.cjs.js",
6
6
  "module": "dist/bot-detector.esm.js",
7
- "browser": "dist/bot-detector.iife.js",
7
+ "browser": "dist/bot-detector.esm.js",
8
8
  "types": "dist/types.d.ts",
9
9
  "exports": {
10
10
  ".": {
11
11
  "types": "./dist/types.d.ts",
12
- "browser": "./dist/bot-detector.iife.js",
13
12
  "import": "./dist/bot-detector.esm.js",
14
13
  "require": "./dist/bot-detector.cjs.js",
15
14
  "default": "./dist/bot-detector.esm.js"
16
- }
15
+ },
16
+ "./iife": "./dist/bot-detector.iife.js",
17
+ "./iife.min": "./dist/bot-detector.iife.min.js"
17
18
  },
18
19
  "files": [
19
20
  "dist",
@@ -91,18 +91,23 @@ class PuppeteerSignal extends Signal {
91
91
 
92
92
  // Check for binding injection pattern
93
93
  // Puppeteer's exposeFunction creates window bindings
94
+ // Exclude __zone_symbol__* (Angular/Zone.js) which are benign
94
95
  const suspiciousBindings = Object.keys(window).filter(key => {
95
- return key.startsWith('__') && typeof window[key] === 'function';
96
+ return key.startsWith('__') &&
97
+ !key.startsWith('__zone_symbol__') &&
98
+ typeof window[key] === 'function';
96
99
  });
97
100
 
98
- if (suspiciousBindings.length > 3) {
101
+ if (suspiciousBindings.length > 5) {
99
102
  indicators.push('suspicious-bindings');
100
103
  confidence = Math.max(confidence, 0.5);
101
104
  }
102
105
 
103
106
  // Check Chrome object anomalies (Puppeteer headless)
107
+ // Note: in a normal Chrome page, window.chrome.runtime exists but runtime.id is
108
+ // only set inside Chrome extensions. Only flag when runtime itself is absent.
104
109
  if (typeof window.chrome !== 'undefined') {
105
- if (!window.chrome.runtime || !window.chrome.runtime.id) {
110
+ if (!window.chrome.runtime) {
106
111
  indicators.push('incomplete-chrome-object');
107
112
  confidence = Math.max(confidence, 0.4);
108
113
  }