/* ============================================================ FLOWSHIELD — Red Team (dynamic scan forms + live API runner) ============================================================ */ /* Wordlist picker: choose a built-in/uploaded dictionary for this category, or paste a custom one. Resolves the chosen list's content into the field value so the existing payload builder ships it as plain text. */ function WordlistField({ f, value, onChange, disabled }) { const [lists, setLists] = useStateL([]); const [src, setSrc] = useStateL(''); // '' engine default · chosen list · '__custom' const [loading, setLoading] = useStateL(false); useEffectL(() => { let alive = true; window.fsApi('/api/wordlists?category=' + encodeURIComponent(f.category), { method: 'GET' }) .then(d => { if (alive) setLists((d && d.wordlists) || []); }) .catch(() => {}); return () => { alive = false; }; }, [f.category]); const pick = async (val) => { setSrc(val); if (val === '' || val === '__custom') { onChange(''); return; } setLoading(true); try { const text = await window.fsApi('/api/wordlists/' + encodeURIComponent(val) + '/content', { method: 'GET' }); onChange(typeof text === 'string' ? text : ''); } catch (e) { onChange(''); } setLoading(false); }; // Optional: load a file from the local disk into the textarea (opt-in via f.upload). const onFile = (e) => { const file = e.target.files && e.target.files[0]; if (!file) { return; } const reader = new FileReader(); reader.onload = () => { setSrc('__custom'); onChange(((value ? value + '\n' : '') + String(reader.result || '')).trim()); }; reader.readAsText(file); e.target.value = ''; }; const chosen = lists.find(l => l.id === src); const count = value ? value.split('\n').filter(s => s.trim() && !s.trim().startsWith('#')).length : 0; const label = ; return (
{label} {f.upload && ( )} {src === '' ? (
Se usará el diccionario incorporado del motor. Sube los tuyos en Ajustes › Wordlists.
) : (
{loading &&
Cargando diccionario…
}