(ip)
| 4656 | if (!mac) return ''; |
| 4657 | const s = encodeURIComponent(ssid || '').replace(/'/g, '%27'); |
| 4658 | return `<a href="javascript:void(0)" onclick="event.stopPropagation();wifiPivotFromDefense('${mac}','${s}')"` |
| 4659 | + ` class="underline decoration-dotted hover:text-white" title="Open in Spectrum Analyzer">${mac}</a>`; |
| 4660 | } |
| 4661 | |
| 4662 | function wifidefRender() { |
| 4663 | const d = _wifidef.data; if (!d) return; |
| 4664 | const [label, cls] = _WIFIDEF_THREAT[d.threat] || ['—', 'bg-slate-700 text-slate-300']; |
| 4665 | const tb = document.getElementById('wifidef-threat'); |
| 4666 | tb.textContent = label; tb.className = 'shrink-0 px-4 py-2 rounded-lg text-sm font-bold ' + cls; |
| 4667 | // Detection cards |
| 4668 | const det = document.getElementById('wifidef-detections'); |
| 4669 | if (!d.detections.length) { |
| 4670 | det.innerHTML = '<div class="glass rounded-xl p-4 text-sm text-green-300 md:col-span-2">✓ No wireless attacks detected in this capture.</div>'; |
| 4671 | } else { |
| 4672 | det.innerHTML = d.detections.map(x => { |
| 4673 | const crit = ['flood', 'evil_twin', 'karma'].includes(x.severity); |
| 4674 | const border = crit ? 'border-l-4 border-red-500' : 'border-l-4 border-amber-500'; |
| 4675 | let title = '', body = ''; |
| 4676 | if (x.type === 'deauth') { |
| 4677 | title = x.severity === 'flood' ? '💥 Deauth/Disassoc FLOOD' : 'Deauth/Disassoc frames seen'; |
| 4678 | const scopeTag = x.scope ? ` <span class="text-gray-500">(${x.scope}${x.unprotected === x.count && x.count ? ', unprotected' : ''})</span>` : ''; |
| 4679 | body = `<div>${x.count} frames.${scopeTag}</div>` + (x.attackers || []).map(a => |
| 4680 | `<div class="font-mono text-[11px] text-gray-400">${_wifidefMacLink(a.src)} → ${a.dst} ×${a.count}</div>`).join(''); |
| 4681 | } else if (x.type === 'beacon_flood') { |
| 4682 | title = x.severity === 'flood' ? '📡 Beacon flood (fake APs)' : '📡 Dense airspace (beacon)'; |
| 4683 | const laTag = (x.la_ratio != null) ? ` · <span class="${x.la_ratio >= 0.5 ? 'text-red-300' : 'text-gray-500'}">${Math.round(x.la_ratio * 100)}% randomized MACs</span>` : ''; |
| 4684 | body = `<div>${x.ssids} SSIDs from ${x.bssids} BSSIDs${laTag}.</div>`; |
| 4685 | } else if (x.type === 'karma') { |
| 4686 | title = '🎣 KARMA / MANA rogue AP'; |
| 4687 | body = `<div class="font-mono text-[11px] text-gray-400">${_wifidefMacLink(x.bssid)}</div><div>answered ${x.ssid_count} SSIDs: ${(x.ssids || []).join(', ')}</div>`; |
no test coverage detected