1/** 2 * Bugsnag Bot Detection Module 3 * 4 * Client-side bot detection to prevent Bugsnag loading for crawlers and bots 5 * while maintaining error monitoring for real users. 6 * 7 * @author Best It <[email protected]> 8 * @version 1.0.0 9 */ 10(function(window, document) { 11 'use strict'; 12 13 // Configuration will be injected by template 14 var config = window.BugsnagBotDetectionConfig || {}; 15 16 // Default configuration 17 var defaultConfig = { 18 enableBotDetection: true, 19 enableDebug: false, 20 enableFallback: true, 21 enablePerformance: false, 22 apiKey: '', 23 releaseStage: 'production', 24 bugsnagUrl: 'https://d2wy8f7a9ursnm.cloudfront.net/v8/bugsnag.min.js', 25 performanceUrl: 'https://d2wy8f7a9ursnm.cloudfront.net/v1/bugsnag-performance.min.js' 26 }; 27 28 // Merge configuration 29 config = Object.assign({}, defaultConfig, config); 30 31 // Comprehensive bot detection patterns 32 var botPatterns = [ 33 // Search Engine Bots (Primary targets for our errors) 34 /bingbot/i, // Microsoft Bing - main culprit 35 /googlebot/i, // Google 36 /slurp/i, // Yahoo 37 /duckduckbot/i, // DuckDuckGo 38 /baiduspider/i, // Baidu 39 /yandexbot/i, // Yandex 40 41 // Social Media Crawlers 42 /facebookexternalhit/i, // Facebook 43 /twitterbot/i, // Twitter 44 /linkedinbot/i, // LinkedIn 45 /whatsapp/i, // WhatsApp 46 /telegrambot/i, // Telegram 47 /discordbot/i, // Discord 48 49 // Monitoring & Performance Tools 50 /uptimerobot/i, // Uptime monitoring 51 /pingdom/i, // Pingdom 52 /gtmetrix/i, // GTmetrix 53 /lighthouse/i, // Google Lighthouse 54 /pagespeed/i, // PageSpeed Insights 55 /webpagetest/i, // WebPageTest 56 57 // SEO & Analysis Tools 58 /semrushbot/i, // SEMrush 59 /ahrefsbot/i, // Ahrefs 60 /mj12bot/i, // Majestic 61 /dotbot/i, // Moz 62 /screaming frog/i, // Screaming Frog 63 64 // Generic Bot Patterns 65 /crawler/i, 66 /spider/i, 67 /bot\b/i, // Word boundary to avoid false positives 68 /scraper/i, 69 /fetcher/i, 70 /scanner/i, 71 72 // Automation Tools (Common sources of errors) 73 /headlesschrome/i, // Headless Chrome 74 /phantomjs/i, // PhantomJS 75 /selenium/i, // Selenium 76 /webdriver/i, // WebDriver 77 /puppeteer/i, // Puppeteer 78 /playwright/i, // Playwright 79 80 // Security Scanners 81 /nikto/i, 82 /nessus/i, 83 /openvas/i, 84 /zap/i, // OWASP ZAP 85 86 // Archive & Backup Services 87 /wayback/i, // Internet Archive 88 /archive\.org/i, 89 /ia_archiver/i 90 ]; 91 92 /** 93 * User agent based bot detection 94 * @returns {boolean} True if bot detected via user agent 95 */ 96 function isBotUserAgent() { 97 var userAgent = navigator.userAgent || ''; 98 99 if (!userAgent) { 100 return true; // Empty user agent is suspicious 101 } 102 103 return botPatterns.some(function(pattern) { 104 return pattern.test(userAgent); 105 }); 106 } 107 108 /** 109 * Browser behavior based bot detection 110 * @returns {boolean} True if bot detected via browser behavior 111 */ 112 function isBotBehavior() { 113 // Check for missing browser properties that bots often lack 114 var checks = [
115 // Window properties 116 !window.outerHeight || window.outerHeight === 0, 117 !window.outerWidth || window.outerWidth === 0, 118 119 // Navigator properties 120 !navigator.plugins || navigator.plugins.length === 0, 121 !navigator.languages || navigator.languages.length === 0, 122 123 // Missing common browser objects 124 typeof window.localStorage === 'undefined', 125 typeof window.sessionStorage === 'undefined', 126 127 // Headless browser detection 128 navigator.webdriver === true, 129 window.navigator.webdriver === true, 130 131 // PhantomJS detection 132 window.callPhantom !== undefined, 133 window._phantom !== undefined, 134 135 // Selenium detection 136 window.document.$cdc_asdjflasutopfhvcZLmcfl_ !== undefined, 137 window.document.documentElement.getAttribute('webdriver') !== null, 138 139 // Puppeteer detection 140 window.chrome && window.chrome.runtime && window.chrome.runtime.onConnect === undefined 141 ]; 142 143 // If more than 2 checks fail, likely a bot 144 var failedChecks = checks.filter(Boolean).length; 145 return failedChecks >= 3; 146 } 147 148 /** 149 * Comprehensive bot detection 150 * @returns {boolean} True if bot detected 151 */ 152 function isBot() { 153 var userAgentBot = isBotUserAgent(); 154 var behaviorBot = isBotBehavior(); 155 156 if (config.enableDebug) { 157 console.log('Bot Detection Results:', { 158 userAgent: navigator.userAgent, 159 userAgentBot: userAgentBot, 160 behaviorBot: behaviorBot, 161 finalDecision: userAgentBot || behaviorBot 162 }); 163 } 164 165 // Primary detection: User agent (most reliable) 166 // Secondary: Behavior analysis (additional confidence) 167 return userAgentBot || behaviorBot; 168 } 169 170 /** 171 * Load Bugsnag script dynamically 172 */ 173 function loadBugsnag() { 174 var script = document.createElement('script'); 175 script.src = config.bugsnagUrl; 176 script.async = true; 177 script.crossOrigin = 'anonymous'; 178 179 script.onload = function() { 180 initializeBugsnag(); 181 }; 182 183 script.onerror = function() { 184 if (config.enableDebug) { 185 console.warn('Failed to load Bugsnag script from:', config.bugsnagUrl); 186 } 187 188 if (config.enableFallback) { 189 initializeFallbackErrorHandler(); 190 } 191 }; 192 193 document.head.appendChild(script); 194 } 195 196 /** 197 * Initialize Bugsnag 198 */ 199 function initializeBugsnag() { 200 try { 201 if (typeof window.Bugsnag === 'undefined') { 202 throw new Error('Bugsnag not available after script load'); 203 } 204 205 window.Bugsnag.start({ 206 apiKey: config.apiKey, 207 releaseStage: config.releaseStage, 208 enabledErrorTypes: { 209 unhandledExceptions: true, 210 unhandledRejections: true 211 }, 212 onError: function(event) { 213 // Additional error filtering 214 var error = event.originalError || event.errors[0]; 215 216 // Filter out known bot-related errors 217 if (error && error.message) { 218 var message = error.message.toLowerCase(); 219 var botErrorPatterns = [ 220 'cannot read property \'register\' of undefined', 221 'cannot read properties of null', 222 'script error', 223 'non-error promise rejection captured' 224 ]; 225 226 if (botErrorPatterns.some(function(pattern) { 227 return message.includes(pattern); 228 })) { 229 if (config.enableDebug) { 230 console.log('Filtered bot-like error:', message); 231 } 232 return false; // Don't report this error 233 } 234 } 235 236 return true; // Report the error 237 }, 238 metadata: { 239 app: { 240 botDetectionVersion: '1.0.0', 241 userAgent: navigator.userAgent, 242 timestamp: new Date().toISOString() 243 } 244 } 245 }); 246 247 // Set up enhanced error handler 248 window.onerror = function myErrorHandler(errorMsg, url, lineNumber) { 249 if (window.Bugsnag) { 250 window.Bugsnag.notify(errorMsg); 251 } 252 return false;
253 }; 254 255 if (config.enableDebug) { 256 console.log('Bugsnag initialized successfully'); 257 } 258 259 // Load performance monitoring if enabled 260 if (config.enablePerformance) { 261 loadBugsnagPerformance(); 262 } 263 264 } catch (error) { 265 if (config.enableDebug) { 266 console.warn('Bugsnag initialization failed:', error); 267 } 268 269 if (config.enableFallback) { 270 initializeFallbackErrorHandler(); 271 } 272 } 273 } 274 275 /** 276 * Load Bugsnag Performance monitoring 277 */ 278 function loadBugsnagPerformance() { 279 import(config.performanceUrl) 280 .then(function(BugsnagPerformance) { 281 if (BugsnagPerformance && BugsnagPerformance.default) { 282 BugsnagPerformance.default.start({ 283 apiKey: config.apiKey, 284 releaseStage: config.releaseStage 285 }); 286 287 if (config.enableDebug) { 288 console.log('Bugsnag Performance initialized successfully'); 289 } 290 } 291 }) 292 .catch(function(error) { 293 if (config.enableDebug) { 294 console.warn('Failed to load Bugsnag Performance:', error); 295 } 296 }); 297 } 298 299 /** 300 * Fallback error handler for when Bugsnag fails 301 */ 302 function initializeFallbackErrorHandler() { 303 window.addEventListener('error', function(event) { 304 if (config.enableDebug) { 305 console.error('Fallback Error Handler:', { 306 message: event.message, 307 filename: event.filename, 308 lineno: event.lineno, 309 colno: event.colno, 310 error: event.error, 311 userAgent: navigator.userAgent, 312 timestamp: new Date().toISOString() 313 }); 314 } 315 }); 316 317 window.addEventListener('unhandledrejection', function(event) { 318 if (config.enableDebug) { 319 console.error('Fallback Promise Rejection Handler:', { 320 reason: event.reason, 321 userAgent: navigator.userAgent, 322 timestamp: new Date().toISOString() 323 }); 324 } 325 }); 326 327 if (config.enableDebug) { 328 console.log('Fallback error handlers initialized'); 329 } 330 } 331 332 /** 333 * Main initialization function 334 */ 335 function initialize() { 336 // Check if bot detection is enabled 337 if (config.enableBotDetection && isBot()) { 338 if (config.enableDebug) { 339 console.log('Bot detected - Bugsnag not loaded:', { 340 userAgent: navigator.userAgent, 341 timestamp: new Date().toISOString() 342 }); 343 } 344 return; // Exit early for bots 345 } 346 347 // Real user detected - load Bugsnag 348 if (config.enableDebug) { 349 console.log('Real user detected - loading Bugsnag:', { 350 userAgent: navigator.userAgent, 351 timestamp: new Date().toISOString() 352 }); 353 } 354 355 loadBugsnag(); 356 } 357 358 // Execute when DOM is ready or immediately if already ready 359 if (document.readyState === 'loading') { 360 document.addEventListener('DOMContentLoaded', initialize); 361 } else { 362 initialize(); 363 } 364 365 // Expose for testing purposes 366 if (config.enableDebug) { 367 window.BugsnagBotDetection = { 368 isBot: isBot, 369 isBotUserAgent: isBotUserAgent, 370 isBotBehavior: isBotBehavior, 371 config: config 372 }; 373 } 374 375})(window, document);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.