()
| 7880 | addConsoleMessage('STP baseline reset — re-learning current root(s) & bridges', 'info'); |
| 7881 | await runStpWatch(); |
| 7882 | } catch (e) { |
| 7883 | addConsoleMessage('Failed to reset STP baseline: ' + e.message, 'error'); |
| 7884 | } |
| 7885 | } |
| 7886 | |
| 7887 | // ---- Relay/Coercion Watch (NTLM relay + auth coercion defense) -------------- |
| 7888 | const _RELAY_VERDICT_STYLE = { |
| 7889 | clean: ['bg-green-950/40 border-green-900 text-green-400', '✓ No coercion, relay, or unsigned-SMB negotiation'], |
| 7890 | 'signing-not-required': ['bg-amber-950/50 border-amber-800 text-amber-300', '⚠ SMB signing not required — captured/coerced NTLM is relayable'], |
| 7891 | 'relay-suspected': ['bg-red-950/60 border-red-800 text-red-300', '🛑 NTLM RELAY suspected — one challenge replayed across servers'], |
| 7892 | 'coercion-attempt': ['bg-red-950/60 border-red-800 text-red-300', '🛑 COERCION — a host is being forced to authenticate (PetitPotam/PrinterBug/…)'], |
| 7893 | unknown: ['bg-slate-800 border-slate-700 text-slate-400', '— Could not determine'], |
| 7894 | }; |
| 7895 | function _relayFillIfaces() { |
| 7896 | const sel = document.getElementById('relay-iface'); |
| 7897 | if (!sel || sel.dataset.filled === '1') return Promise.resolve(); |
| 7898 | return fetchAPI('/api/net/interfaces').then(x => { |
| 7899 | (x.interfaces || []).forEach(i => { |
| 7900 | const o = document.createElement('option'); |
| 7901 | o.value = i.name; |
| 7902 | const tag = i.type === 'wifi' ? ' (WiFi)' : i.type === 'ethernet' ? ' (LAN)' : (i.type ? ' (' + i.type + ')' : ''); |
| 7903 | o.textContent = i.name + tag; |
| 7904 | sel.appendChild(o); |
| 7905 | }); |
| 7906 | sel.dataset.filled = '1'; |
| 7907 | }).catch(() => {}); |
| 7908 | } |
| 7909 | async function runRelayWatch() { |
| 7910 | const out = document.getElementById('relay-results'); |
| 7911 | if (!out) return; |
| 7912 | const btn = (typeof event !== 'undefined' && event && event.target) ? event.target : null; |
| 7913 | const ifaceSel = document.getElementById('relay-iface'); |
| 7914 | const iface = ifaceSel && ifaceSel.value ? ifaceSel.value : ''; |
| 7915 | const secsEl = document.getElementById('relay-secs'); |
| 7916 | const secs = secsEl && secsEl.value ? secsEl.value : '20'; |
no test coverage detected