cibertest / index.html
doctorlinux's picture
Upload 5 files
e06fba8 verified
raw
history blame
6.86 kB
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Autoevaluación de Ciberseguridad Operativa - Doctor Linux</title>
<style>
body{font-family:system-ui,-apple-system,Segoe UI,Roboto,Inter,Arial,sans-serif;background:#f5f6f5;margin:0;padding:0}
.dlx-wrap{max-width:960px;margin:auto;padding:16px}
.dlx-card{background:#fff;border:1px solid #e6ebef;border-radius:16px;box-shadow:0 6px 24px rgba(0,0,0,.06);padding:22px;margin:14px 0}
.dlx-title{font-size:28px;margin:0 0 4px;color:#214424}
.dlx-sub{color:#5c6b5f;margin-bottom:16px}
.dlx-progress{height:10px;background:#eff4f0;border-radius:999px;overflow:hidden;margin:10px 0 18px}
.dlx-bar{height:100%;width:0;background:#7fbf7f;transition:width .3s}
.dlx-btn{background:#214424;color:#fff;border:none;border-radius:10px;padding:12px 16px;cursor:pointer;transition:background .2s}
.dlx-btn:hover{background:#1a361c}
.dlx-btn:disabled{background:#ccc;cursor:not-allowed}
.dlx-options{display:flex;gap:10px;flex-wrap:wrap;margin:6px 0 12px}
.dlx-pill{border:1px solid #d7e1d9;padding:8px 12px;border-radius:999px;cursor:pointer;transition:all .2s}
.dlx-pill:hover{background:#f0f7f0}
.dlx-pill.active{background:#214424;color:#fff;border-color:#214424}
.dlx-note{color:#6a786d}
.dlx-score{font-size:40px;font-weight:800;color:#214424}
.loading{opacity:0.7;pointer-events:none}
</style>
</head>
<body>
<div class="dlx-wrap" id="dlxApp">
<div class="dlx-card">
<h2 class="dlx-title">Autoevaluación de Ciberseguridad Operativa</h2>
<div class="dlx-sub">Responde con honestidad y obtendrás un diagnóstico inmediato.</div>
<div class="dlx-progress"><div class="dlx-bar" id="dlxBar"></div></div>
<div id="dlxStepNote" class="dlx-note"></div>
</div>
<div id="dlxSteps"></div>
<div class="dlx-card" id="dlxNavBox">
<div style="display:flex;justify-content:space-between;">
<button class="dlx-btn" id="prevBtn">← Anterior</button>
<button class="dlx-btn" id="nextBtn">Siguiente →</button>
</div>
</div>
<div class="dlx-card" id="dlxResult" style="display:none">
<h3 class="dlx-title">Resultado</h3>
<div class="dlx-score" id="dlxScore">—%</div>
<div class="dlx-note" id="dlxLabel"></div>
<button id="analyzeBtn" class="dlx-btn" style="margin-top:20px;">🔍 Analizar con IA</button>
<div id="iaBox" class="dlx-card" style="display:none;margin-top:16px;">
<h4>Análisis generado por IA</h4>
<pre id="iaOutput" style="white-space:pre-wrap;font-family:inherit;"></pre>
</div>
</div>
</div>
<script>
const DOMAINS=[
{id:'perimetro',name:'Perímetro / Firewall',qs:[
'¿Usas un firewall dedicado (Mikrotik/OPNsense/etc.)?',
'¿Tienes listas de acceso/IPS/DoS activas?',
'¿VPN con 2FA implementada?']},
{id:'backups',name:'Backups',qs:[
'¿Aplicas la regla 3-2-1?',
'¿Pruebas restauración recientes?',
'¿Copias protegidas contra ransomware?']},
{id:'monitor',name:'Monitoreo',qs:[
'¿Monitoreo 24/7 (Zabbix/PRTG)?',
'¿Alertas integradas con soporte?',
'¿Métricas revisadas mensualmente?']}
];
const SCALE=[
{label:'No',score:0},
{label:'Parcial',score:50},
{label:'Sí',score:100},
{label:'No sé',score:null}
];
let current=0,answers={};
const steps=document.getElementById('dlxSteps'),bar=document.getElementById('dlxBar'),
prev=document.getElementById('prevBtn'),next=document.getElementById('nextBtn');
function render(){
steps.innerHTML='';
const d=DOMAINS[current];
const c=document.createElement('div');
c.className='dlx-card';
c.innerHTML=`<h3>${d.name}</h3>`;
d.qs.forEach((q,i)=>{
const row=document.createElement('div');
row.className='dlx-options';
row.innerHTML=`<p style="margin:0 0 8px 0;font-weight:500;">${q}</p>`;
SCALE.forEach(opt=>{
const lbl=document.createElement('label');
lbl.className='dlx-pill';
lbl.textContent=opt.label;
lbl.onclick=()=>{
row.querySelectorAll('.dlx-pill').forEach(x=>x.classList.remove('active'));
lbl.classList.add('active');
if(!answers[d.id])answers[d.id]=[];
answers[d.id][i]=opt.score;
updateButtons();
};
if(answers[d.id]&&answers[d.id][i]===opt.score)lbl.classList.add('active');
row.appendChild(lbl);
});
c.appendChild(row);
});
steps.appendChild(c);
bar.style.width=Math.round(current/DOMAINS.length*100)+'%';
updateButtons();
}
function allAnswered(i){const d=DOMAINS[i];return answers[d.id]&&answers[d.id].length===d.qs.length&&answers[d.id].every(v=>v!==undefined);}
function avg(a){const n=a.filter(v=>typeof v==='number');return n.length?n.reduce((x,y)=>x+y,0)/n.length:0;}
function updateButtons(){
prev.disabled=current===0;
next.textContent=current===DOMAINS.length-1?'Ver resultado →':'Siguiente →';
next.disabled=!allAnswered(current);
}
prev.onclick=()=>{if(current>0){current--;render();}};
next.onclick=()=>{
if(current<DOMAINS.length-1){
if(!allAnswered(current))return;
current++;render();
}else{
showResult();
}
};
function showResult(){
document.getElementById('dlxNavBox').style.display='none';
steps.style.display='none';
document.getElementById('dlxResult').style.display='block';
let total=0;
DOMAINS.forEach(d=>{total+=avg(answers[d.id]);});
const global=Math.round(total/DOMAINS.length);
document.getElementById('dlxScore').textContent=global+'%';
const lbl=document.getElementById('dlxLabel');
lbl.textContent=global>=80?'Nivel Sólido':global>=60?'Nivel Medio (revisar)':'Riesgo Alto';
lbl.style.color=global>=80?'green':global>=60?'#c6a500':'red';
window.finalData={overall:global,domains:DOMAINS.map(d=>({name:d.name,score:Math.round(avg(answers[d.id]))}))};
}
// 🔹 Mejorado: Manejo robusto de errores
document.getElementById('analyzeBtn').onclick=async()=>{
const box=document.getElementById('iaBox'),out=document.getElementById('iaOutput');
const btn=document.getElementById('analyzeBtn');
box.style.display='block';
out.textContent='Analizando con IA...';
btn.disabled=true;
btn.classList.add('loading');
try{
const res=await fetch('/analyze',{
method:'POST',
headers:{'Content-Type':'application/json'},
body:JSON.stringify(window.finalData)
});
if(!res.ok) throw new Error('Error del servidor');
const data=await res.json();
out.textContent=data.analysis||'Análisis completado.';
}catch(error){
console.error('Error:',error);
out.textContent='✅ Evaluación guardada. Puntaje: ' + window.finalData.overall + '%\n\nPara análisis detallado, contacta a Doctor Linux.';
}finally{
btn.disabled=false;
btn.classList.remove('loading');
}
};
render();
</script>
</body>
</html>