您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Advanced website technology stack analysis with performance metrics, security audit, SEO analysis, and real-time monitoring
// ==UserScript== // @name Tech Stack Detector // @namespace http://tampermonkey.net/ // @version 2.0 // @description Advanced website technology stack analysis with performance metrics, security audit, SEO analysis, and real-time monitoring // @author Tech Detector // @match *://*/* // @grant GM_addStyle // @grant GM_xmlhttpRequest // @grant GM_setValue // @grant GM_getValue // @grant GM_notification // @run-at document-end // ==/UserScript== (function() { 'use strict'; // Add enhanced CSS styles GM_addStyle(` #tech-stack-detector { position: fixed; top: 20px; right: 20px; width: 450px; max-height: 85vh; background: linear-gradient(135deg, #1a1a1a 0%, #2d2d2d 100%); border: 2px solid #444; border-radius: 12px; color: #fff; font-family: 'SF Mono', 'Monaco', 'Inconsolata', 'Roboto Mono', monospace; font-size: 12px; z-index: 10000; overflow: hidden; box-shadow: 0 8px 32px rgba(0,0,0,0.6), 0 0 0 1px rgba(255,255,255,0.1); backdrop-filter: blur(10px); transition: all 0.3s ease; } #tech-stack-header { background: linear-gradient(90deg, #333 0%, #444 100%); padding: 12px 15px; border-bottom: 1px solid #555; display: flex; justify-content: space-between; align-items: center; box-shadow: 0 2px 10px rgba(0,0,0,0.3); } #tech-stack-tabs { display: flex; background: #2a2a2a; border-bottom: 1px solid #444; } .tab { flex: 1; padding: 8px 12px; background: #2a2a2a; border: none; color: #aaa; cursor: pointer; font-size: 11px; transition: all 0.2s ease; position: relative; } .tab.active { background: #3a3a3a; color: #4CAF50; box-shadow: inset 0 -2px 0 #4CAF50; } .tab:hover { background: #353535; color: #fff; } #tech-stack-content { padding: 15px; max-height: 55vh; overflow-y: auto; scrollbar-width: thin; scrollbar-color: #555 #2a2a2a; } #tech-stack-content::-webkit-scrollbar { width: 6px; } #tech-stack-content::-webkit-scrollbar-track { background: #2a2a2a; } #tech-stack-content::-webkit-scrollbar-thumb { background: #555; border-radius: 3px; } .tech-category { margin-bottom: 20px; border-bottom: 1px solid #333; padding-bottom: 12px; } .tech-category h3 { color: #4CAF50; margin: 0 0 10px 0; font-size: 14px; display: flex; align-items: center; gap: 8px; } .tech-item { display: flex; justify-content: space-between; align-items: center; margin: 8px 0; padding: 6px 10px; background: rgba(255,255,255,0.03); border-radius: 6px; border-left: 3px solid #4CAF50; transition: all 0.2s ease; } .tech-item:hover { background: rgba(255,255,255,0.08); transform: translateX(3px); } .tech-name { color: #fff; font-weight: 600; display: flex; align-items: center; gap: 6px; } .tech-version { color: #FFB74D; font-weight: 500; } .tech-confidence { color: #81C784; font-size: 10px; background: rgba(129, 199, 132, 0.2); padding: 2px 6px; border-radius: 10px; margin-left: 6px; } .security-good { color: #4CAF50; } .security-warning { color: #FF9800; } .security-bad { color: #F44336; } .security-critical { color: #D32F2F; background: rgba(211, 47, 47, 0.1); } .metric-score { font-weight: bold; padding: 2px 6px; border-radius: 4px; font-size: 11px; } .score-excellent { background: #4CAF50; color: white; } .score-good { background: #8BC34A; color: white; } .score-average { background: #FF9800; color: white; } .score-poor { background: #F44336; color: white; } .toggle-btn, .export-btn { background: linear-gradient(45deg, #4CAF50, #45a049); border: none; color: white; padding: 6px 12px; border-radius: 6px; cursor: pointer; font-size: 11px; margin-left: 5px; transition: all 0.2s ease; } .export-btn { background: linear-gradient(45deg, #2196F3, #1976D2); } .toggle-btn:hover, .export-btn:hover { transform: translateY(-1px); box-shadow: 0 4px 12px rgba(0,0,0,0.3); } .close-btn { background: linear-gradient(45deg, #f44336, #d32f2f); border: none; color: white; padding: 6px 10px; border-radius: 6px; cursor: pointer; margin-left: 5px; : all 0.2s ease; } .close-btn:hover { transform: translateY(-1px); box-shadow: 0 4px 12px rgba(244, 67, 54, 0.3); } .loading { color: #FFB74D; font-style: italic; text-align: center; padding: 20px; display: flex; align-items: center; justify-content: center; gap: 10px; } .loading::before { content: ''; width: 20px; height: 20px; border: 2px solid #FFB74D; border-top: 2px solid transparent; border-radius: 50%; animation: spin 1s linear infinite; } @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } .vulnerability { background: rgba(244, 67, 54, 0.1); border-left-color: #F44336 !important; border-left-width: 4px; } .performance-metric { display: grid; grid-template-columns: 1fr auto auto; gap: 10px; align-items: center; } .api-endpoint { font-family: monospace; background: rgba(33, 150, 243, 0.1); padding: 4px 8px; border-radius: 4px; font-size: 10px; margin: 2px 0; } .tech-icon { width: 16px; height: 16px; display: inline-block; } .floating-toggle { position: fixed; top: 20px; right: 20px; background: linear-gradient(45deg, #4CAF50, #45a049); border: none; color: white; padding: 12px; border-radius: 50%; cursor: pointer; z-index: 10001; font-size: 18px; box-shadow: 0 4px 20px rgba(76, 175, 80, 0.4); transition: all 0.3s ease; } .floating-toggle:hover { transform: scale(1.1); box-shadow: 0 6px 25px rgba(76, 175, 80, 0.6); } .notification { position: fixed; top: 80px; right: 20px; background: #333; color: white; padding: 10px 15px; border-radius: 6px; z-index: 10002; animation: slideIn 0.3s ease; } @keyframes slideIn { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } } .tab-content { display: none; } .tab-content.active { display: block; } .progress-bar { width: 100%; height: 4px; background: #333; border-radius: 2px; overflow: hidden; margin: 5px 0; } .progress-fill { height: 100%; background: linear-gradient(90deg, #4CAF50, #8BC34A); transition: width 0.3s ease; } `); class AdvancedTechStackDetector { constructor() { this.results = { frontend: [], backend: [], database: [], cdn: [], hosting: [], security: [], performance: [], seo: [], analytics: [], apis: [], buildTools: [], thirdParty: [], vulnerabilities: [] }; this.networkRequests = []; this.performanceMetrics = {}; this.isVisible = false; this.activeTab = 'overview'; this.monitoringEnabled = false; this.init(); } init() { this.createUI(); this.startNetworkMonitoring(); // Run detection asynchronously to avoid blocking UI setTimeout(() => { this.detectTechnologies(); this.analyzePerformance(); this.analyzeSEO(); // Update UI after detection is complete setTimeout(() => { this.updateUI(); }, 100); }, 100); } createUI() { const container = document.createElement('div'); container.id = 'tech-stack-detector'; container.style.display = 'none'; container.innerHTML = ` <div id="tech-stack-header"> <span>🚀 Advanced Tech Stack Detector Pro</span> <div> <button class="export-btn" id="export-btn">📊 Export</button> </div> </div> <div id="tech-stack-tabs"> <button class="tab active" data-tab="overview">Overview</button> <button class="tab" data-tab="security">Security</button> <button class="tab" data-tab="performance">Performance</button> <button class="tab" data-tab="seo">SEO</button> <button class="tab" data-tab="network">Network</button> </div> <div id="tech-stack-content"> <div class="loading">🔄 Performing deep analysis...</div> </div> `; document.body.appendChild(container); // Create enhanced toggle button const toggleBtn = document.createElement('button'); toggleBtn.innerHTML = '🚀'; toggleBtn.className = 'floating-toggle'; toggleBtn.onclick = () => this.toggleVisibility(); document.body.appendChild(toggleBtn); window.techDetector = this; // Add event listeners for all buttons this.setupEventListeners(); } setupEventListeners() { // Wait a bit to ensure DOM is ready setTimeout(() => { // Setup tab listeners const tabs = document.querySelectorAll('.tab'); tabs.forEach(tab => { tab.addEventListener('click', (e) => { const tabName = e.target.getAttribute('data-tab'); this.switchTab(tabName); }); }); // Setup header button listeners const exportBtn = document.getElementById('export-btn'); if (exportBtn) { exportBtn.addEventListener('click', () => this.exportResults()); } }, 100); } startNetworkMonitoring() { // Monitor fetch requests const originalFetch = window.fetch; window.fetch = (...args) => { const startTime = performance.now(); this.networkRequests.push({ url: args[0], method: args[1]?.method || 'GET', timestamp: Date.now(), type: 'fetch' }); return originalFetch.apply(this, args).then(response => { const endTime = performance.now(); this.networkRequests[this.networkRequests.length - 1].duration = endTime - startTime; this.networkRequests[this.networkRequests.length - 1].status = response.status; return response; }); }; // Monitor XMLHttpRequest const originalXHR = window.XMLHttpRequest; window.XMLHttpRequest = function() { const xhr = new originalXHR(); const originalOpen = xhr.open; const originalSend = xhr.send; xhr.open = function(method, url) { this._method = method; this._url = url; this._startTime = performance.now(); return originalOpen.apply(this, arguments); }; xhr.send = function() { const detector = window.techDetector; if (detector) { detector.networkRequests.push({ url: this._url, method: this._method, timestamp: Date.now(), type: 'xhr' }); } this.addEventListener('loadend', () => { if (detector && this._startTime) { const duration = performance.now() - this._startTime; const lastRequest = detector.networkRequests[detector.networkRequests.length - 1]; if (lastRequest) { lastRequest.duration = duration; lastRequest.status = this.status; } } }); return originalSend.apply(this, arguments); }; return xhr; }; } async detectTechnologies() { // Enhanced Frontend Detection await this.detectAdvancedFrontend(); // Enhanced Backend Detection await this.detectAdvancedBackend(); // Build Tools Detection await this.detectBuildTools(); // Third-party Services Detection await this.detectThirdPartyServices(); // CDN & Hosting Detection await this.detectCDNAndHosting(); // API Detection await this.detectAPIs(); // Security Analysis await this.analyzeAdvancedSecurity(); // Database Detection this.detectDatabase(); // Vulnerability Assessment await this.assessVulnerabilities(); // Detection complete - UI will be updated from init() } async detectAdvancedFrontend() { const checks = [ // React Ecosystem { name: 'React', detect: () => { if (window.React) { return { version: window.React.version || 'Unknown', confidence: 'High', details: this.getReactDetails() }; } if (document.querySelector('[data-reactroot], [data-react-helmet]') || document.querySelector('div[id="root"], div[id="app"]')) { return { version: 'Unknown', confidence: 'Medium' }; } return null; } }, // Next.js { name: 'Next.js', detect: () => { if (window.__NEXT_DATA__ || window.__nextjs || document.querySelector('script[src*="/_next/"]')) { const version = window.__NEXT_DATA__?.buildId ? 'Detected' : 'Unknown'; return { version, confidence: 'High' }; } return null; } }, // Vue.js Ecosystem { name: 'Vue.js', detect: () => { if (window.Vue) { return { version: window.Vue.version || 'Unknown', confidence: 'High', details: this.getVueDetails() }; } if (document.querySelector('[data-v-]') || document.querySelector('[v-]')) { return { version: 'Unknown', confidence: 'Medium' }; } return null; } }, // Nuxt.js { name: 'Nuxt.js', detect: () => { if (window.$nuxt || window.__NUXT__ || document.querySelector('script[src*="/_nuxt/"]')) { return { version: 'Detected', confidence: 'High' }; } return null; } }, // Angular Ecosystem { name: 'Angular', detect: () => { if (window.ng || window.angular) { const version = window.ng?.version?.full || window.angular?.version?.full || 'Unknown'; return { version, confidence: 'High', details: this.getAngularDetails() }; } if (document.querySelector('[ng-app], [ng-controller], app-root, [ng-version]')) { return { version: 'Unknown', confidence: 'Medium' }; } return null; } }, // Svelte/SvelteKit { name: 'Svelte', detect: () => { if (window.__SVELTE__ || document.querySelector('[data-svelte]')) { return { version: 'Detected', confidence: 'High' }; } return null; } }, // Solid.js { name: 'Solid.js', detect: () => { if (window.Solid || document.querySelector('[data-solid]')) { return { version: 'Detected', confidence: 'High' }; } return null; } }, // Alpine.js { name: 'Alpine.js', detect: () => { if (window.Alpine || document.querySelector('[x-data], [x-show], [x-if]')) { return { version: window.Alpine?.version || 'Unknown', confidence: 'High' }; } return null; } }, // Lit { name: 'Lit', detect: () => { if (window.lit || document.querySelector('[lit]')) { return { version: 'Detected', confidence: 'High' }; } return null; } }, // jQuery and plugins { name: 'jQuery', detect: () => { if (window.jQuery || window.$) { const version = (window.jQuery || window.$).fn?.jquery || 'Unknown'; return { version, confidence: 'High', details: this.getJQueryPlugins() }; } return null; } }, // CSS Frameworks { name: 'Bootstrap', detect: () => { if (window.bootstrap || document.querySelector('.bootstrap, [class*="bs-"]')) { const version = window.bootstrap?.Tooltip?.VERSION || 'Unknown'; return { version, confidence: 'High' }; } if (document.querySelector('.container, .row, .col-, [class*="btn-"]')) { return { version: 'Unknown', confidence: 'Medium' }; } return null; } }, { name: 'Tailwind CSS', detect: () => { const tailwindClasses = ['tw-', 'text-', 'bg-', 'p-', 'm-', 'flex', 'grid', 'hidden', 'block']; const hasTailwind = tailwindClasses.some(cls => document.querySelector(`[class*="${cls}"]`) ); if (hasTailwind) { return { version: 'Unknown', confidence: 'Medium' }; } return null; } }, { name: 'Bulma', detect: () => { if (document.querySelector('.bulma, .column, .hero, [class*="is-"]')) { return { version: 'Unknown', confidence: 'Medium' }; } return null; } }, { name: 'Foundation', detect: () => { if (window.Foundation || document.querySelector('[class*="foundation"], .grid-x, .cell')) { return { version: 'Unknown', confidence: 'Medium' }; } return null; } }, // State Management { name: 'Redux', detect: () => { if (window.__REDUX_DEVTOOLS_EXTENSION__ || window.Redux) { return { version: 'Detected', confidence: 'High' }; } return null; } }, { name: 'MobX', detect: () => { if (window.mobx || window.__mobxDidRunLazyInitializers) { return { version: 'Detected', confidence: 'High' }; } return null; } }, { name: 'Zustand', detect: () => { if (window.zustand) { return { version: 'Detected', confidence: 'High' }; } return null; } }, // UI Libraries { name: 'Material-UI', detect: () => { if (document.querySelector('[class*="MuiBox"], [class*="MuiButton"]') || window.mui) { return { version: 'Unknown', confidence: 'Medium' }; } return null; } }, { name: 'Ant Design', detect: () => { if (document.querySelector('[class*="ant-"], .antd') || window.antd) { return { version: 'Unknown', confidence: 'Medium' }; } return null; } }, { name: 'Chakra UI', detect: () => { if (document.querySelector('[class*="chakra"], [class*="css-"]')) { return { version: 'Unknown', confidence: 'Low' }; } return null; } }, // Animation Libraries { name: 'GSAP', detect: () => { if (window.gsap || window.TweenMax || window.TweenLite) { return { version: window.gsap?.version || 'Unknown', confidence: 'High' }; } return null; } }, { name: 'Framer Motion', detect: () => { if (document.querySelector('[data-framer-motion]') || window.framerMotion) { return { version: 'Detected', confidence: 'High' }; } return null; } }, // Testing Libraries (in dev mode) { name: 'Jest', detect: () => { if (window.jest || window.__coverage__) { return { version: 'Detected', confidence: 'High' }; } return null; } }, // Module Bundlers (runtime detection) { name: 'Webpack', detect: () => { if (window.webpackJsonp || window.__webpack_require__ || document.querySelector('script[src*="webpack"]')) { return { version: 'Detected', confidence: 'High' }; } return null; } }, { name: 'Vite', detect: () => { if (window.__vite__ || document.querySelector('script[type="module"][src*="vite"]')) { return { version: 'Detected', confidence: 'High' }; } return null; } }, { name: 'Parcel', detect: () => { if (window.parcelRequire || document.querySelector('script[src*="parcel"]')) { return { version: 'Detected', confidence: 'High' }; } return null; } } ]; checks.forEach(check => { const result = check.detect(); if (result) { this.results.frontend.push({ name: check.name, version: result.version, confidence: result.confidence, details: result.details || null }); } }); } detectBackend() { const scripts = Array.from(document.querySelectorAll('script[src]')); const links = Array.from(document.querySelectorAll('link[href]')); const metas = Array.from(document.querySelectorAll('meta')); // Check for common backend indicators const indicators = [ { name: 'WordPress', pattern: /wp-content|wp-includes|wordpress/i }, { name: 'Drupal', pattern: /drupal|sites\/default/i }, { name: 'Joomla', pattern: /joomla|com_content/i }, { name: 'Magento', pattern: /magento|mage\/js/i }, { name: 'Shopify', pattern: /shopify|cdn\.shopify/i }, { name: 'Django', pattern: /django|__admin/i }, { name: 'Rails', pattern: /rails|ruby/i }, { name: 'ASP.NET', pattern: /aspnet|webresource\.axd/i }, { name: 'PHP', pattern: /\.php/i } ]; const allContent = document.documentElement.outerHTML; const allSources = [...scripts.map(s => s.src), ...links.map(l => l.href)].join(' '); indicators.forEach(indicator => { if (indicator.pattern.test(allContent + allSources)) { this.results.backend.push({ name: indicator.name, version: 'Unknown', confidence: 'Medium' }); } }); // Check generator meta tag const generator = metas.find(m => m.name === 'generator'); if (generator && generator.content) { this.results.backend.push({ name: generator.content.split(' ')[0], version: generator.content.split(' ')[1] || 'Unknown', confidence: 'High' }); } } async detectCDNAndHosting() { const scripts = Array.from(document.querySelectorAll('script[src]')); const links = Array.from(document.querySelectorAll('link[href]')); const allSources = [...scripts.map(s => s.src), ...links.map(l => l.href)]; // Enhanced CDN Detection const cdnPatterns = [ { name: 'Cloudflare', pattern: /cloudflare|cdnjs\.cloudflare|cf-ray/i, confidence: 'High' }, { name: 'AWS CloudFront', pattern: /cloudfront\.net|amazonaws\.com/i, confidence: 'High' }, { name: 'Google Cloud CDN', pattern: /googleapis\.com|gstatic\.com|googleusercontent/i, confidence: 'High' }, { name: 'jsDelivr', pattern: /jsdelivr\.net/i, confidence: 'High' }, { name: 'unpkg', pattern: /unpkg\.com/i, confidence: 'High' }, { name: 'MaxCDN', pattern: /maxcdn\.bootstrapcdn|stackpath\.bootstrapcdn/i, confidence: 'High' }, { name: 'KeyCDN', pattern: /keycdn\.com/i, confidence: 'High' }, { name: 'BunnyCDN', pattern: /bunnycdn\.com/i, confidence: 'High' }, { name: 'Fastly', pattern: /fastly\.com|fastlylb/i, confidence: 'High' }, { name: 'Azure CDN', pattern: /azureedge\.net/i, confidence: 'High' }, { name: 'Akamai', pattern: /akamai\.net|edgesuite\.net/i, confidence: 'High' }, { name: 'Cachefly', pattern: /cachefly\.net/i, confidence: 'High' } ]; cdnPatterns.forEach(cdn => { if (allSources.some(src => cdn.pattern.test(src))) { this.results.cdn.push({ name: cdn.name, version: 'Active', confidence: cdn.confidence }); } }); const currentUrl = window.location.href; const hostname = window.location.hostname; // Enhanced hosting platform detection const hostingPatterns = [ { name: 'Vercel', pattern: /vercel\.app|vercel\.com|_vercel/i, confidence: 'High' }, { name: 'Netlify', pattern: /netlify\.app|netlify\.com|_netlify/i, confidence: 'High' }, { name: 'GitHub Pages', pattern: /github\.io|githubusercontent/i, confidence: 'High' }, { name: 'Heroku', pattern: /herokuapp\.com|herokucdn/i, confidence: 'High' }, { name: 'Firebase Hosting', pattern: /firebase\.com|firebaseapp\.com|web\.app/i, confidence: 'High' }, { name: 'Cloudflare Pages', pattern: /pages\.dev/i, confidence: 'High' }, { name: 'AWS S3', pattern: /s3\.amazonaws\.com|s3-website/i, confidence: 'High' }, { name: 'Surge.sh', pattern: /surge\.sh/i, confidence: 'High' }, { name: 'Now.sh', pattern: /now\.sh/i, confidence: 'High' }, { name: 'DigitalOcean', pattern: /digitalocean\.com|digitaloceanspaces/i, confidence: 'Medium' }, { name: 'Linode', pattern: /linode\.com/i, confidence: 'Medium' }, { name: 'Railway', pattern: /railway\.app/i, confidence: 'High' }, { name: 'Render', pattern: /render\.com|onrender\.com/i, confidence: 'High' } ]; hostingPatterns.forEach(hosting => { if (hosting.pattern.test(currentUrl + hostname)) { this.results.hosting.push({ name: hosting.name, version: 'Active', confidence: hosting.confidence }); } }); } async analyzeAdvancedSecurity() { const security = []; // HTTPS check if (window.location.protocol === 'https:') { security.push({ name: 'HTTPS', version: '✓ Enabled', confidence: 'High', status: 'good' }); } else { security.push({ name: 'HTTPS', version: '✗ Disabled', confidence: 'High', status: 'bad' }); } // CSP Analysis const cspMeta = document.querySelector('meta[http-equiv="Content-Security-Policy"]'); if (cspMeta) { const cspValue = cspMeta.content; const hasUnsafeInline = cspValue.includes("'unsafe-inline'"); const hasUnsafeEval = cspValue.includes("'unsafe-eval'"); security.push({ name: 'Content Security Policy', version: hasUnsafeInline || hasUnsafeEval ? '⚠ Weak CSP' : '✓ Strong CSP', confidence: 'High', status: hasUnsafeInline || hasUnsafeEval ? 'warning' : 'good' }); } else { security.push({ name: 'Content Security Policy', version: '✗ Not found', confidence: 'High', status: 'warning' }); } // Mixed content detection const mixedContent = Array.from(document.querySelectorAll('script[src], link[href], img[src], iframe[src]')) .some(el => { const src = el.src || el.href; return src && src.startsWith('http:') && window.location.protocol === 'https:'; }); security.push({ name: 'Mixed Content', version: mixedContent ? '⚠ Detected' : '✓ None detected', confidence: 'High', status: mixedContent ? 'warning' : 'good' }); // Cookie security analysis const cookies = document.cookie.split(';'); const secureFlag = cookies.some(cookie => cookie.includes('Secure')); const httpOnlyFlag = cookies.some(cookie => cookie.includes('HttpOnly')); const sameSiteFlag = cookies.some(cookie => cookie.includes('SameSite')); if (cookies.length > 1) { security.push({ name: 'Cookie Security', version: `${secureFlag ? '✓' : '✗'} Secure, ${httpOnlyFlag ? '✓' : '✗'} HttpOnly, ${sameSiteFlag ? '✓' : '✗'} SameSite`, confidence: 'Medium', status: secureFlag && sameSiteFlag ? 'good' : 'warning' }); } // Check for common vulnerabilities await this.checkCommonVulnerabilities(security); this.results.security = security; } async checkCommonVulnerabilities(security) { // Check for potential XSS vulnerabilities const scripts = Array.from(document.querySelectorAll('script')); const inlineScripts = scripts.filter(s => !s.src && s.innerHTML); const hasInlineScripts = inlineScripts.length > 0; if (hasInlineScripts) { security.push({ name: 'Inline Scripts', version: `⚠ ${inlineScripts.length} inline scripts detected`, confidence: 'Medium', status: 'warning' }); } // Check for eval usage const pageContent = document.documentElement.outerHTML; if (pageContent.includes('eval(') || pageContent.includes('Function(')) { security.push({ name: 'Dynamic Code Execution', version: '⚠ eval() or Function() detected', confidence: 'Medium', status: 'warning' }); } // Check for document.write usage if (pageContent.includes('document.write')) { security.push({ name: 'Document Write', version: '⚠ document.write() detected', confidence: 'Medium', status: 'warning' }); } // Check for iframe security const iframes = document.querySelectorAll('iframe'); const unsafeIframes = Array.from(iframes).filter(iframe => !iframe.hasAttribute('sandbox') || iframe.src.startsWith('http:') ); if (unsafeIframes.length > 0) { security.push({ name: 'Iframe Security', version: `⚠ ${unsafeIframes.length} potentially unsafe iframes`, confidence: 'Medium', status: 'warning' }); } } detectDatabase() { // Enhanced database inference const backendNames = this.results.backend.map(b => b.name.toLowerCase()); const pageContent = document.documentElement.outerHTML.toLowerCase(); const dbInferences = [ { indicators: ['wordpress', 'woocommerce', 'drupal', 'joomla'], db: 'MySQL', confidence: 'High' }, { indicators: ['django', 'postgresql'], db: 'PostgreSQL', confidence: 'High' }, { indicators: ['rails', 'ruby'], db: 'PostgreSQL/MySQL', confidence: 'Medium' }, { indicators: ['asp.net', 'microsoft', 'iis'], db: 'SQL Server', confidence: 'Medium' }, { indicators: ['mongodb', 'mongoose', 'mongo'], db: 'MongoDB', confidence: 'High' }, { indicators: ['redis', 'cache'], db: 'Redis', confidence: 'Medium' }, { indicators: ['firebase', 'firestore'], db: 'Firestore', confidence: 'High' }, { indicators: ['supabase'], db: 'Supabase (PostgreSQL)', confidence: 'High' }, { indicators: ['planetscale'], db: 'PlanetScale (MySQL)', confidence: 'High' }, { indicators: ['fauna', 'faunadb'], db: 'FaunaDB', confidence: 'High' }, { indicators: ['dynamodb', 'aws'], db: 'DynamoDB', confidence: 'Medium' }, { indicators: ['sqlite'], db: 'SQLite', confidence: 'Medium' }, { indicators: ['oracle'], db: 'Oracle Database', confidence: 'Medium' }, { indicators: ['cassandra'], db: 'Apache Cassandra', confidence: 'Medium' }, { indicators: ['elasticsearch', 'elastic'], db: 'Elasticsearch', confidence: 'Medium' } ]; dbInferences.forEach(inference => { const isDetected = inference.indicators.some(indicator => backendNames.includes(indicator) || pageContent.includes(indicator) ); if (isDetected) { this.results.database.push({ name: inference.db, version: 'Inferred', confidence: inference.confidence }); } }); } async assessVulnerabilities() { const vulnerabilities = []; // Check for known vulnerable libraries const knownVulnerabilities = [ { library: 'jQuery', versions: ['1.0.0', '1.1.0', '1.2.0', '1.3.0', '1.4.0', '1.5.0', '1.6.0', '1.7.0', '1.8.0', '1.9.0'], risk: 'High', issue: 'Multiple XSS vulnerabilities' }, { library: 'Angular', versions: ['1.0.0', '1.1.0', '1.2.0', '1.3.0', '1.4.0', '1.5.0'], risk: 'Medium', issue: 'XSS and injection vulnerabilities' } ]; this.results.frontend.forEach(tech => { const vuln = knownVulnerabilities.find(v => v.library === tech.name); if (vuln && vuln.versions.some(v => tech.version.includes(v))) { vulnerabilities.push({ name: `${tech.name} Vulnerability`, version: `${vuln.risk} Risk: ${vuln.issue}`, confidence: 'High', status: 'critical' }); } }); // Check for outdated libraries (basic check) const currentYear = new Date().getFullYear(); this.results.frontend.forEach(tech => { if (tech.version.includes('1.') || tech.version.includes('2.')) { vulnerabilities.push({ name: `Potentially Outdated: ${tech.name}`, version: `Version ${tech.version} may be outdated`, confidence: 'Low', status: 'warning' }); } }); this.results.vulnerabilities = vulnerabilities; } switchTab(tabName) { this.activeTab = tabName; // Update tab buttons document.querySelectorAll('.tab').forEach(tab => { tab.classList.remove('active'); if (tab.getAttribute('data-tab') === tabName) { tab.classList.add('active'); } }); this.updateUI(); } updateUI() { try { const content = document.getElementById('tech-stack-content'); if (!content) { console.error('Content container not found'); return; } let html = ''; switch (this.activeTab) { case 'overview': html = this.generateOverviewHTML(); break; case 'security': html = this.generateSecurityHTML(); break; case 'performance': html = this.generatePerformanceHTML(); break; case 'seo': html = this.generateSEOHTML(); break; case 'network': html = this.generateNetworkHTML(); break; default: html = this.generateOverviewHTML(); } content.innerHTML = html; this.applyStatusColors(); } catch (error) { console.error('Error updating UI:', error); const content = document.getElementById('tech-stack-content'); if (content) { content.innerHTML = `<div class="tech-item" style="color: #f44336;">Error loading content: ${error.message}</div>`; } } } generateOverviewHTML() { let html = '<div class="tab-content active">'; const categories = [ { key: 'frontend', title: 'Frontend Technologies', icon: '⚛️' }, { key: 'backend', title: 'Backend Technologies', icon: '🔧' }, { key: 'database', title: 'Databases', icon: '🗄️' }, { key: 'cdn', title: 'CDN & Services', icon: '🌐' }, { key: 'hosting', title: 'Hosting Platform', icon: '☁️' }, { key: 'buildTools', title: 'Build Tools', icon: '🔨' }, { key: 'thirdParty', title: 'Third-party Services', icon: '🔌' }, { key: 'apis', title: 'APIs & Protocols', icon: '📡' } ]; categories.forEach(category => { const items = this.results[category.key]; if (items && items.length > 0) { html += this.generateCategoryHTML(category.title, category.icon, items); } }); // Summary statistics const totalTechs = Object.values(this.results).flat().length; html += ` <div class="tech-category"> <h3>📊 Summary</h3> <div class="tech-item"> <span class="tech-name">Total Technologies Detected</span> <span class="tech-version">${totalTechs}</span> </div> <div class="tech-item"> <span class="tech-name">Network Requests Monitored</span> <span class="tech-version">${this.networkRequests.length}</span> </div> <div class="tech-item"> <span class="tech-name">Page Load Time</span> <span class="tech-version">${((this.performanceMetrics.loadComplete || 0) / 1000).toFixed(2)}s</span> </div> </div> `; html += '</div>'; return html; } generateSecurityHTML() { let html = '<div class="tab-content active">'; // Security analysis if (this.results.security && this.results.security.length > 0) { html += this.generateCategoryHTML('Security Analysis', '🔒', this.results.security); } else { html += ` <div class="tech-category"> <h3>🔒 Security Analysis</h3> <div class="tech-item"> <span class="tech-name">Running security analysis...</span> <span class="tech-version">Please wait</span> </div> </div> `; } // Vulnerabilities if (this.results.vulnerabilities && this.results.vulnerabilities.length > 0) { html += this.generateCategoryHTML('Potential Vulnerabilities', '⚠️', this.results.vulnerabilities, true); } else { html += ` <div class="tech-category"> <h3>⚠️ Potential Vulnerabilities</h3> <div class="tech-item"> <span class="tech-name">No obvious vulnerabilities detected</span> <span class="tech-version security-good">✓ Good</span> </div> </div> `; } // Security recommendations html += ` <div class="tech-category"> <h3>💡 Security Recommendations</h3> <div class="tech-item"> <span class="tech-name">Enable HTTPS</span> <span class="tech-version">${window.location.protocol === 'https:' ? '✓ Done' : '❌ Required'}</span> </div> <div class="tech-item"> <span class="tech-name">Implement CSP</span> <span class="tech-version">${document.querySelector('meta[http-equiv="Content-Security-Policy"]') ? '✓ Done' : '⚠️ Recommended'}</span> </div> <div class="tech-item"> <span class="tech-name">Use Secure Cookies</span> <span class="tech-version">${document.cookie.includes('Secure') ? '✓ Done' : '⚠️ Recommended'}</span> </div> </div> `; html += '</div>'; return html; } generatePerformanceHTML() { let html = '<div class="tab-content active">'; // Performance metrics if (this.results.performance && this.results.performance.length > 0) { html += ` <div class="tech-category"> <h3>⚡ Web Vitals</h3> ${this.results.performance.map(metric => ` <div class="tech-item performance-metric"> <span class="tech-name">${metric.name}</span> <span class="tech-version">${metric.value}</span> <span class="metric-score score-${metric.score}">${metric.score.toUpperCase()}</span> </div> `).join('')} </div> `; } else { html += ` <div class="tech-category"> <h3>⚡ Web Vitals</h3> <div class="tech-item"> <span class="tech-name">Analyzing performance...</span> <span class="tech-version">Please wait</span> </div> </div> `; } // Detailed performance metrics if (this.performanceMetrics) { html += ` <div class="tech-category"> <h3>📊 Performance Metrics</h3> <div class="tech-item"> <span class="tech-name">DOM Content Loaded</span> <span class="tech-version">${((this.performanceMetrics.domContentLoaded || 0) / 1000).toFixed(2)}s</span> </div> <div class="tech-item"> <span class="tech-name">Page Load Complete</span> <span class="tech-version">${((this.performanceMetrics.loadComplete || 0) / 1000).toFixed(2)}s</span> </div> <div class="tech-item"> <span class="tech-name">First Paint</span> <span class="tech-version">${((this.performanceMetrics.firstPaint || 0) / 1000).toFixed(2)}s</span> </div> <div class="tech-item"> <span class="tech-name">First Contentful Paint</span> <span class="tech-version">${((this.performanceMetrics.firstContentfulPaint || 0) / 1000).toFixed(2)}s</span> </div> <div class="tech-item"> <span class="tech-name">Resource Count</span> <span class="tech-version">${this.performanceMetrics.resourceCount || 0}</span> </div> <div class="tech-item"> <span class="tech-name">Total Transfer Size</span> <span class="tech-version">${((this.performanceMetrics.totalTransferSize || 0) / 1024 / 1024).toFixed(2)} MB</span> </div> </div> `; } // Performance recommendations html += ` <div class="tech-category"> <h3>💡 Performance Recommendations</h3> <div class="tech-item"> <span class="tech-name">Optimize Images</span> <span class="tech-version">${document.querySelectorAll('img').length} images found</span> </div> <div class="tech-item"> <span class="tech-name">Minify Resources</span> <span class="tech-version">${document.querySelectorAll('script:not([src*="min"]), link[href*=".css"]:not([href*="min"])').length} unminified resources</span> </div> <div class="tech-item"> <span class="tech-name">Enable Compression</span> <span class="tech-version">Check server configuration</span> </div> </div> `; html += '</div>'; return html; } generateSEOHTML() { let html = '<div class="tab-content active">'; if (this.results.seo && this.results.seo.length > 0) { html += this.generateCategoryHTML('SEO Analysis', '🔍', this.results.seo); } else { html += ` <div class="tech-category"> <h3>🔍 SEO Analysis</h3> <div class="tech-item"> <span class="tech-name">Analyzing SEO...</span> <span class="tech-version">Please wait</span> </div> </div> `; } // Additional SEO insights html += ` <div class="tech-category"> <h3>📈 SEO Insights</h3> <div class="tech-item"> <span class="tech-name">Page Load Speed</span> <span class="tech-version ${(this.performanceMetrics?.loadComplete || 0) < 3000 ? 'security-good' : 'security-warning'}"> ${(this.performanceMetrics?.loadComplete || 0) < 3000 ? 'Good' : 'Needs Improvement'} </span> </div> <div class="tech-item"> <span class="tech-name">Mobile Responsive</span> <span class="tech-version">${document.querySelector('meta[name="viewport"]') ? '✓ Yes' : '❌ No'}</span> </div> <div class="tech-item"> <span class="tech-name">Social Media Ready</span> <span class="tech-version">${document.querySelectorAll('meta[property^="og:"], meta[name^="twitter:"]').length > 0 ? '✓ Yes' : '❌ No'}</span> </div> </div> `; html += '</div>'; return html; } generateNetworkHTML() { let html = '<div class="tab-content active">'; // Network requests summary html += ` <div class="tech-category"> <h3>🌐 Network Activity</h3> <div class="tech-item"> <span class="tech-name">Total Requests</span> <span class="tech-version">${(this.networkRequests || []).length}</span> </div> <div class="tech-item"> <span class="tech-name">Average Response Time</span> <span class="tech-version">${this.calculateAverageResponseTime()}ms</span> </div> <div class="tech-item"> <span class="tech-name">Failed Requests</span> <span class="tech-version">${(this.networkRequests || []).filter(r => r.status >= 400).length}</span> </div> </div> `; // Recent API calls if (this.networkRequests && this.networkRequests.length > 0) { html += ` <div class="tech-category"> <h3>📡 Recent API Calls</h3> ${this.networkRequests.slice(-10).map(req => ` <div class="tech-item"> <div class="api-endpoint">${req.method || 'GET'} ${this.truncateUrl(req.url)}</div> <span class="tech-version ${(req.status >= 400) ? 'security-bad' : 'security-good'}"> ${req.status || 'Pending'} ${req.duration ? `(${req.duration.toFixed(0)}ms)` : ''} </span> </div> `).join('')} </div> `; } else { html += ` <div class="tech-category"> <h3>📡 Network Monitoring</h3> <div class="tech-item"> <span class="tech-name">Monitoring network requests...</span> <span class="tech-version">Make some requests to see activity</span> </div> </div> `; } html += '</div>'; return html; } generateCategoryHTML(title, icon, items, isVulnerability = false) { return ` <div class="tech-category"> <h3>${icon} ${title}</h3> ${items.map(item => ` <div class="tech-item ${isVulnerability ? 'vulnerability' : ''}"> <span class="tech-name">${item.name}</span> <div> <span class="tech-version ${item.status ? `security-${item.status}` : ''}">${item.version}</span> <span class="tech-confidence">${item.confidence}</span> </div> </div> ${item.details ? `<div class="tech-details">${item.details.join(', ')}</div>` : ''} `).join('')} </div> `; } applyStatusColors() { // Enhanced status color application this.results.security.forEach((item, index) => { if (item.status) { const elements = document.querySelectorAll('.tech-version'); elements.forEach(el => { if (el.textContent.includes(item.version)) { el.className = `tech-version security-${item.status}`; } }); } }); } calculateAverageResponseTime() { if (!this.networkRequests || this.networkRequests.length === 0) return 0; const validRequests = this.networkRequests.filter(r => r.duration); if (validRequests.length === 0) return 0; const total = validRequests.reduce((sum, req) => sum + req.duration, 0); return (total / validRequests.length).toFixed(0); } truncateUrl(url) { if (!url) return 'Unknown'; if (url.length > 50) { return url.substring(0, 47) + '...'; } return url; } exportResults() { const exportData = { url: window.location.href, timestamp: new Date().toISOString(), technologies: this.results, performance: this.performanceMetrics, networkRequests: this.networkRequests.length, summary: { totalTechnologies: Object.values(this.results).flat().length, securityScore: this.calculateSecurityScore(), performanceScore: this.calculatePerformanceScore() } }; // Create and download JSON file const blob = new Blob([JSON.stringify(exportData, null, 2)], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `tech-stack-analysis-${new Date().getTime()}.json`; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); this.showNotification('📊 Analysis exported successfully!'); } calculateSecurityScore() { const securityItems = this.results.security; if (securityItems.length === 0) return 0; const goodItems = securityItems.filter(item => item.status === 'good').length; return Math.round((goodItems / securityItems.length) * 100); } calculatePerformanceScore() { const loadTime = this.performanceMetrics.loadComplete || 0; if (loadTime < 1000) return 100; if (loadTime < 2000) return 80; if (loadTime < 3000) return 60; if (loadTime < 5000) return 40; return 20; } showNotification(message) { const notification = document.createElement('div'); notification.className = 'notification'; notification.textContent = message; document.body.appendChild(notification); setTimeout(() => { notification.remove(); }, 3000); } close() { const container = document.getElementById('tech-stack-detector'); container.style.display = 'none'; this.isVisible = false; } // Helper functions for detailed analysis getReactDetails() { const details = []; if (window.__REACT_DEVTOOLS_GLOBAL_HOOK__) { details.push('React DevTools detected'); } if (window.ReactDOM) { details.push(`ReactDOM v${window.ReactDOM.version || 'Unknown'}`); } if (document.querySelector('[data-react-helmet]')) { details.push('React Helmet'); } return details; } getVueDetails() { const details = []; if (window.__VUE_DEVTOOLS_GLOBAL_HOOK__) { details.push('Vue DevTools detected'); } if (window.Vuex) { details.push('Vuex State Management'); } if (window.VueRouter) { details.push('Vue Router'); } return details; } getAngularDetails() { const details = []; if (window.ng) { details.push(`Angular CLI: ${window.ng.version?.full || 'Unknown'}`); } if (document.querySelector('[ng-version]')) { const version = document.querySelector('[ng-version]').getAttribute('ng-version'); details.push(`Version: ${version}`); } return details; } getJQueryPlugins() { const plugins = []; if (window.jQuery) { const $ = window.jQuery; if ($.fn.modal) plugins.push('Bootstrap Modal'); if ($.fn.tooltip) plugins.push('Tooltip'); if ($.fn.carousel) plugins.push('Carousel'); if ($.fn.datepicker) plugins.push('Datepicker'); if ($.fn.select2) plugins.push('Select2'); if ($.fn.slick) plugins.push('Slick Slider'); if ($.fn.owlCarousel) plugins.push('Owl Carousel'); } return plugins; } async detectAdvancedBackend() { const scripts = Array.from(document.querySelectorAll('script[src]')); const links = Array.from(document.querySelectorAll('link[href]')); const metas = Array.from(document.querySelectorAll('meta')); const headers = await this.analyzeHeaders(); // Enhanced backend detection patterns const indicators = [ // CMS Systems { name: 'WordPress', pattern: /wp-content|wp-includes|wordpress|wp-json/i, confidence: 'High' }, { name: 'Drupal', pattern: /drupal|sites\/default|misc\/drupal/i, confidence: 'High' }, { name: 'Joomla', pattern: /joomla|com_content|index\.php\?option=com/i, confidence: 'High' }, { name: 'Magento', pattern: /magento|mage\/js|checkout\/cart/i, confidence: 'High' }, { name: 'Shopify', pattern: /shopify|cdn\.shopify|assets\/shopify/i, confidence: 'High' }, { name: 'Wix', pattern: /wix\.com|wixstatic|wixsite/i, confidence: 'High' }, { name: 'Squarespace', pattern: /squarespace|static1\.squarespace/i, confidence: 'High' }, { name: 'Webflow', pattern: /webflow|assets\.website-files/i, confidence: 'High' }, // Frameworks { name: 'Django', pattern: /django|__admin|csrfmiddlewaretoken/i, confidence: 'High' }, { name: 'Flask', pattern: /flask|werkzeug/i, confidence: 'Medium' }, { name: 'FastAPI', pattern: /fastapi|swagger|openapi\.json/i, confidence: 'Medium' }, { name: 'Ruby on Rails', pattern: /rails|ruby|authenticity_token/i, confidence: 'High' }, { name: 'Laravel', pattern: /laravel|laravel_session|_token/i, confidence: 'High' }, { name: 'Symfony', pattern: /symfony|sf_toolbar/i, confidence: 'Medium' }, { name: 'CodeIgniter', pattern: /codeigniter|ci_session/i, confidence: 'Medium' }, { name: 'CakePHP', pattern: /cakephp|cake\/|CAKEPHP/i, confidence: 'Medium' }, { name: 'ASP.NET', pattern: /aspnet|webresource\.axd|__doPostBack/i, confidence: 'High' }, { name: 'ASP.NET Core', pattern: /aspnetcore|__RequestVerificationToken/i, confidence: 'High' }, { name: 'Express.js', pattern: /express|connect\.sid/i, confidence: 'Medium' }, { name: 'Koa.js', pattern: /koa/i, confidence: 'Low' }, { name: 'Nest.js', pattern: /nestjs/i, confidence: 'Medium' }, { name: 'Spring Boot', pattern: /spring|jsessionid|spring-boot/i, confidence: 'Medium' }, { name: 'Strapi', pattern: /strapi|\/api\/|application\/json/i, confidence: 'Low' }, // Languages { name: 'PHP', pattern: /\.php|PHPSESSID/i, confidence: 'High' }, { name: 'Python', pattern: /\.py|python|django|flask/i, confidence: 'Medium' }, { name: 'Node.js', pattern: /node|npm|\.js/i, confidence: 'Low' }, { name: 'Java', pattern: /\.jsp|\.java|jsessionid|struts/i, confidence: 'Medium' }, { name: 'C#', pattern: /\.aspx|\.ashx|viewstate/i, confidence: 'High' }, { name: 'Go', pattern: /golang|\.go/i, confidence: 'Low' }, { name: 'Rust', pattern: /\.rs|rust/i, confidence: 'Low' }, // Servers { name: 'Apache', pattern: /apache|httpd/i, confidence: 'Medium' }, { name: 'Nginx', pattern: /nginx/i, confidence: 'Medium' }, { name: 'IIS', pattern: /iis|microsoft-iis/i, confidence: 'Medium' }, { name: 'Cloudflare', pattern: /cloudflare|cf-ray/i, confidence: 'High' } ]; const allContent = document.documentElement.outerHTML; const allSources = [...scripts.map(s => s.src), ...links.map(l => l.href)].join(' '); const allText = allContent + allSources + JSON.stringify(headers); indicators.forEach(indicator => { if (indicator.pattern.test(allText)) { this.results.backend.push({ name: indicator.name, version: this.extractVersion(allText, indicator.name) || 'Unknown', confidence: indicator.confidence }); } }); // Check generator meta tag const generator = metas.find(m => m.name === 'generator'); if (generator && generator.content) { const parts = generator.content.split(' '); this.results.backend.push({ name: parts[0], version: parts[1] || 'Unknown', confidence: 'High' }); } // Check powered-by headers if (headers['x-powered-by']) { this.results.backend.push({ name: headers['x-powered-by'], version: 'Detected from headers', confidence: 'High' }); } } async detectBuildTools() { const scripts = Array.from(document.querySelectorAll('script[src]')); const buildToolPatterns = [ { name: 'Webpack', pattern: /webpack|chunk|bundle\.js/i }, { name: 'Vite', pattern: /vite|@vite/i }, { name: 'Parcel', pattern: /parcel/i }, { name: 'Rollup', pattern: /rollup/i }, { name: 'Gulp', pattern: /gulp/i }, { name: 'Grunt', pattern: /grunt/i }, { name: 'Browserify', pattern: /browserify/i }, { name: 'esbuild', pattern: /esbuild/i }, { name: 'Snowpack', pattern: /snowpack/i }, { name: 'Turbopack', pattern: /turbopack/i } ]; const allSources = scripts.map(s => s.src).join(' '); const pageContent = document.documentElement.outerHTML; buildToolPatterns.forEach(tool => { if (tool.pattern.test(allSources + pageContent)) { this.results.buildTools.push({ name: tool.name, version: 'Detected', confidence: 'Medium' }); } }); // Check for source maps if (scripts.some(s => s.src.includes('.map') || pageContent.includes('sourceMap'))) { this.results.buildTools.push({ name: 'Source Maps', version: 'Enabled', confidence: 'High' }); } } async detectThirdPartyServices() { const scripts = Array.from(document.querySelectorAll('script[src]')); const allSources = scripts.map(s => s.src).join(' '); const pageContent = document.documentElement.outerHTML; const services = [ // Analytics { name: 'Google Analytics', pattern: /google-analytics|gtag|ga\.js|analytics\.js/i, category: 'analytics' }, { name: 'Google Tag Manager', pattern: /googletagmanager|gtm\.js/i, category: 'analytics' }, { name: 'Facebook Pixel', pattern: /facebook|fbevents|connect\.facebook/i, category: 'analytics' }, { name: 'Hotjar', pattern: /hotjar/i, category: 'analytics' }, { name: 'Mixpanel', pattern: /mixpanel/i, category: 'analytics' }, { name: 'Segment', pattern: /segment|analytics\.min\.js/i, category: 'analytics' }, { name: 'Adobe Analytics', pattern: /adobe|omniture|sitecatalyst/i, category: 'analytics' }, // Payment Processors { name: 'Stripe', pattern: /stripe|js\.stripe\.com/i, category: 'payment' }, { name: 'PayPal', pattern: /paypal|paypalobjects/i, category: 'payment' }, { name: 'Square', pattern: /square|squareup/i, category: 'payment' }, { name: 'Klarna', pattern: /klarna/i, category: 'payment' }, { name: 'Razorpay', pattern: /razorpay/i, category: 'payment' }, // Chat & Support { name: 'Intercom', pattern: /intercom|widget\.intercom/i, category: 'support' }, { name: 'Zendesk', pattern: /zendesk|zdassets/i, category: 'support' }, { name: 'Crisp', pattern: /crisp\.chat/i, category: 'support' }, { name: 'Drift', pattern: /drift\.com/i, category: 'support' }, { name: 'LiveChat', pattern: /livechat|livechatinc/i, category: 'support' }, // CDNs & Services { name: 'Cloudinary', pattern: /cloudinary/i, category: 'media' }, { name: 'Imgix', pattern: /imgix/i, category: 'media' }, { name: 'Twilio', pattern: /twilio/i, category: 'communication' }, { name: 'SendGrid', pattern: /sendgrid/i, category: 'email' }, { name: 'Mailchimp', pattern: /mailchimp/i, category: 'email' }, // Social Media { name: 'Twitter Widgets', pattern: /twitter|twimg|platform\.twitter/i, category: 'social' }, { name: 'LinkedIn Insights', pattern: /linkedin|snap\.licdn/i, category: 'social' }, { name: 'Instagram', pattern: /instagram|instagramstatic/i, category: 'social' }, // Ad Networks { name: 'Google AdSense', pattern: /googlesyndication|adsense|googleadservices/i, category: 'advertising' }, { name: 'Google Ads', pattern: /googleads|adnxs|doubleclick/i, category: 'advertising' }, { name: 'Amazon Associates', pattern: /amazon-adsystem/i, category: 'advertising' }, // Performance & Monitoring { name: 'Sentry', pattern: /sentry/i, category: 'monitoring' }, { name: 'LogRocket', pattern: /logrocket/i, category: 'monitoring' }, { name: 'New Relic', pattern: /newrelic/i, category: 'monitoring' }, { name: 'Datadog', pattern: /datadog|datadoghq/i, category: 'monitoring' }, // Authentication { name: 'Auth0', pattern: /auth0/i, category: 'auth' }, { name: 'Firebase Auth', pattern: /firebase|firebaseapp/i, category: 'auth' }, { name: 'Okta', pattern: /okta/i, category: 'auth' }, // Maps { name: 'Google Maps', pattern: /maps\.googleapis|maps\.google/i, category: 'maps' }, { name: 'Mapbox', pattern: /mapbox/i, category: 'maps' }, { name: 'Leaflet', pattern: /leaflet/i, category: 'maps' } ]; services.forEach(service => { if (service.pattern.test(allSources + pageContent)) { const categoryArray = this.results[service.category] || this.results.thirdParty; categoryArray.push({ name: service.name, version: 'Active', confidence: 'High', category: service.category }); } }); } async detectAPIs() { // Analyze network requests for API patterns const apiPatterns = [ { name: 'REST API', pattern: /\/api\/|\/rest\/|\.json/i }, { name: 'GraphQL', pattern: /\/graphql|query.*{|mutation.*{/i }, { name: 'WebSocket', pattern: /websocket|socket\.io|ws:|wss:/i }, { name: 'gRPC', pattern: /grpc|\.proto/i }, { name: 'SOAP', pattern: /soap|wsdl|\.asmx/i }, { name: 'JSON-RPC', pattern: /json-rpc|jsonrpc/i } ]; const allRequests = this.networkRequests.map(req => req.url).join(' '); const pageContent = document.documentElement.outerHTML; apiPatterns.forEach(api => { if (api.pattern.test(allRequests + pageContent)) { this.results.apis.push({ name: api.name, version: 'Detected', confidence: 'Medium' }); } }); // Check for WebSocket connections if (window.WebSocket || window.io) { this.results.apis.push({ name: 'WebSocket', version: 'Active', confidence: 'High' }); } // Check for Service Workers (PWA APIs) if ('serviceWorker' in navigator) { navigator.serviceWorker.getRegistrations().then(registrations => { if (registrations.length > 0) { this.results.apis.push({ name: 'Service Worker', version: 'Active', confidence: 'High' }); } }); } } extractVersion(content, technology) { const patterns = { 'jQuery': /jquery[\/\-](\d+\.\d+\.\d+)/i, 'Bootstrap': /bootstrap[\/\-](\d+\.\d+\.\d+)/i, 'React': /react[\/\-](\d+\.\d+\.\d+)/i, 'Vue': /vue[\/\-](\d+\.\d+\.\d+)/i, 'Angular': /angular[\/\-](\d+\.\d+\.\d+)/i }; const pattern = patterns[technology]; if (pattern) { const match = content.match(pattern); return match ? match[1] : null; } return null; } async analyzeHeaders() { // Since we can't access headers directly in userscript, // we'll use alternative methods to infer server information const headers = {}; // Check for CSP headers via meta tags const cspMeta = document.querySelector('meta[http-equiv="Content-Security-Policy"]'); if (cspMeta) { headers['content-security-policy'] = cspMeta.content; } // Check for other security headers via meta tags const stsHeader = document.querySelector('meta[http-equiv="Strict-Transport-Security"]'); if (stsHeader) { headers['strict-transport-security'] = stsHeader.content; } return headers; } async analyzePerformance() { try { if ('performance' in window) { const navigation = performance.getEntriesByType('navigation')[0]; const paint = performance.getEntriesByType('paint'); this.performanceMetrics = { domContentLoaded: (navigation?.domContentLoadedEventEnd - navigation?.domContentLoadedEventStart) || 0, loadComplete: (navigation?.loadEventEnd - navigation?.loadEventStart) || 0, firstPaint: paint.find(p => p.name === 'first-paint')?.startTime || 0, firstContentfulPaint: paint.find(p => p.name === 'first-contentful-paint')?.startTime || 0, resourceCount: performance.getEntriesByType('resource').length || 0, totalTransferSize: this.calculateTotalTransferSize() }; // Web Vitals estimation this.analyzeWebVitals(); } else { // Fallback when performance API is not available this.performanceMetrics = { domContentLoaded: 0, loadComplete: 0, firstPaint: 0, firstContentfulPaint: 0, resourceCount: document.querySelectorAll('script, link, img').length, totalTransferSize: 0 }; this.results.performance = [{ name: 'Performance API', value: 'Not available', score: 'unknown', confidence: 'High' }]; } } catch (error) { console.warn('Performance analysis failed:', error); this.performanceMetrics = { domContentLoaded: 0, loadComplete: 0, firstPaint: 0, firstContentfulPaint: 0, resourceCount: 0, totalTransferSize: 0 }; } } analyzeWebVitals() { const vitals = []; // Largest Contentful Paint (estimated) const lcp = this.performanceMetrics.firstContentfulPaint || 0; vitals.push({ name: 'Largest Contentful Paint (est.)', value: `${(lcp / 1000).toFixed(2)}s`, score: this.getPerformanceScore(lcp, [2500, 4000]), confidence: 'Medium' }); // First Input Delay (estimated from load time) const fid = this.performanceMetrics.domContentLoaded || 0; vitals.push({ name: 'First Input Delay (est.)', value: `${(fid / 1000).toFixed(2)}s`, score: this.getPerformanceScore(fid, [100, 300]), confidence: 'Low' }); // Cumulative Layout Shift (basic check) const hasLayoutShift = document.querySelectorAll('[style*="position: absolute"], [style*="position: fixed"]').length > 10; vitals.push({ name: 'Cumulative Layout Shift', value: hasLayoutShift ? 'Potential issues' : 'Good', score: hasLayoutShift ? 'poor' : 'good', confidence: 'Low' }); this.results.performance = vitals; } getPerformanceScore(value, thresholds) { if (value <= thresholds[0]) return 'excellent'; if (value <= thresholds[1]) return 'good'; if (value <= thresholds[1] * 2) return 'average'; return 'poor'; } calculateTotalTransferSize() { try { if ('performance' in window) { return performance.getEntriesByType('resource') .reduce((total, resource) => total + (resource.transferSize || 0), 0); } return 0; } catch (error) { console.warn('Failed to calculate transfer size:', error); return 0; } } async analyzeSEO() { const seoMetrics = []; // Title tag analysis const title = document.querySelector('title'); if (title) { const titleLength = title.textContent.length; seoMetrics.push({ name: 'Title Tag', value: `${titleLength} characters`, score: titleLength >= 30 && titleLength <= 60 ? 'good' : 'warning', confidence: 'High' }); } else { seoMetrics.push({ name: 'Title Tag', value: 'Missing', score: 'poor', confidence: 'High' }); } // Meta description const metaDesc = document.querySelector('meta[name="description"]'); if (metaDesc) { const descLength = metaDesc.content.length; seoMetrics.push({ name: 'Meta Description', value: `${descLength} characters`, score: descLength >= 120 && descLength <= 160 ? 'good' : 'warning', confidence: 'High' }); } else { seoMetrics.push({ name: 'Meta Description', value: 'Missing', score: 'poor', confidence: 'High' }); } // Heading structure const headings = document.querySelectorAll('h1, h2, h3, h4, h5, h6'); const h1Count = document.querySelectorAll('h1').length; seoMetrics.push({ name: 'Heading Structure', value: `${headings.length} headings, ${h1Count} H1`, score: h1Count === 1 ? 'good' : 'warning', confidence: 'High' }); // Images with alt text const images = document.querySelectorAll('img'); const imagesWithAlt = document.querySelectorAll('img[alt]'); if (images.length > 0) { const altPercentage = (imagesWithAlt.length / images.length * 100).toFixed(0); seoMetrics.push({ name: 'Image Alt Text', value: `${altPercentage}% of ${images.length} images`, score: altPercentage > 90 ? 'good' : altPercentage > 70 ? 'warning' : 'poor', confidence: 'High' }); } // Structured data const structuredData = document.querySelectorAll('script[type="application/ld+json"]'); seoMetrics.push({ name: 'Structured Data', value: structuredData.length > 0 ? `${structuredData.length} schemas` : 'None detected', score: structuredData.length > 0 ? 'good' : 'warning', confidence: 'High' }); // Open Graph tags const ogTags = document.querySelectorAll('meta[property^="og:"]'); seoMetrics.push({ name: 'Open Graph Tags', value: ogTags.length > 0 ? `${ogTags.length} tags` : 'None detected', score: ogTags.length >= 4 ? 'good' : ogTags.length > 0 ? 'warning' : 'poor', confidence: 'High' }); // Twitter Card tags const twitterTags = document.querySelectorAll('meta[name^="twitter:"]'); seoMetrics.push({ name: 'Twitter Cards', value: twitterTags.length > 0 ? `${twitterTags.length} tags` : 'None detected', score: twitterTags.length >= 3 ? 'good' : twitterTags.length > 0 ? 'warning' : 'poor', confidence: 'High' }); // Canonical URL const canonical = document.querySelector('link[rel="canonical"]'); seoMetrics.push({ name: 'Canonical URL', value: canonical ? 'Present' : 'Missing', score: canonical ? 'good' : 'warning', confidence: 'High' }); this.results.seo = seoMetrics; } toggleVisibility() { const container = document.getElementById('tech-stack-detector'); this.isVisible = !this.isVisible; container.style.display = this.isVisible ? 'block' : 'none'; if (this.isVisible) { this.showNotification('🚀 Tech Stack Detector activated!'); } } } // Initialize the advanced detector function initializeDetector() { if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', () => { new AdvancedTechStackDetector(); }); } else { new AdvancedTechStackDetector(); } } // Start initialization with error handling try { initializeDetector(); } catch (error) { console.error('Advanced Tech Stack Detector failed to initialize:', error); if (typeof GM_notification !== 'undefined') { GM_notification('Tech Stack Detector failed to initialize. Check console for details.', 'Error'); } } })();