// PEN Landing — Vulnerabilidades & Soluciones sections.
// All evidence panes are now illustrative (not raw terminal output) so a
// non-technical reader gets it at a glance.
const { useState: useStateV, useEffect: useEffectV } = React;
// ════════════════════════════════════════════════════════════════════
// Evidence renderers — one per attack
// ════════════════════════════════════════════════════════════════════
function VulnEvidence({ example, severity }) {
if (!example) return null;
const wrap = (inner, cap) =>
;
switch (example.type) {
case "email":return wrap( , example.caption);
case "slides":return wrap( , example.caption);
case "doors":return wrap( , example.caption);
case "passwords":return wrap( , example.caption);
case "network":return wrap( , example.caption);
case "backup":return wrap( , example.caption);
default:return null;
}
}
// ── 1. Phishing email mock (kept, with highlight + caption) ──────────
function EvEmail({ e }) {
return (
De:
{e.from}
⚠ dominio falso
Asunto:
{e.subject}
{e.body.split("\n").map((l, i) =>
{l || "\u00A0"}
)}
▸ Remitente: no verificado
▸ Urgencia: sospechosa
);
}
// ── 2. Ransomware — auto-cycling 4-scene slideshow ───────────────────
function EvSlides() {
const [idx, setIdx] = useStateV(0);
useEffectV(() => {
const t = setInterval(() => setIdx((i) => (i + 1) % 4), 2200);
return () => clearInterval(t);
}, []);
const scenes = [
{
tag: "08:42",
title: "Llega un correo",
body:
},
{
tag: "08:43",
title: "Empleado abre el PDF",
body:
},
{
tag: "03:00",
title: "Cifrado en silencio",
body:
},
{
tag: "08:00",
title: "Pide rescate",
body:
}];
return (
{scenes.map((s, i) =>
{s.tag}
{s.title}
{s.body}
)}
{scenes.map((_, i) =>
)}
);
}
function RansomScene1() {
return (
Cliente Acme ayer
Factura · pago pendiente 08:42
Newsletter sector 08:30
📎 factura-2025-Q1.pdf
);
}
function RansomScene2() {
return (
▸ malware.exe · ejecutando en segundo plano
);
}
function RansomScene3() {
return (
{["clientes.db", "facturas.xlsx", "nominas.pdf", "contratos.zip", "fotos/", "backup.bak"].map((f, i) =>
{f}
.lockbit
)}
);
}
function RansomScene4() {
return (
!
TUS ARCHIVOS ESTÁN CIFRADOS
Paga 2.4 BTC en 48 horas o todo se pierde.
47:59:23
);
}
// ── 3. RDP / SSH — door metaphor: open server vs closed server ───────
function EvDoors() {
return (
TU SERVIDOR HOY
Puerta abierta
Cualquier bot encuentra tu IP y prueba a entrar 24/7.
▸ 1.847 intentos hoy
CON PEN
Acceso solo por VPN
Cerrado a internet. Solo entra tu equipo, autenticado y verificado.
▸ 0 expuestos
);
}
// ── 4. Passwords — leaked-password notification cards ────────────────
function EvPasswords() {
const rows = [
{ who: "director@", service: "LinkedIn", year: "2021", pwd: "Verano2018!", changed: false },
{ who: "ana@", service: "Adobe", year: "2019", pwd: "ana1234", changed: false },
{ who: "compras@", service: "Dropbox", year: "2022", pwd: "Compras2020", changed: false }];
return (
▸ Filtraciones públicas encontradas
3 / 12 cuentas
{rows.map((r, i) =>
{r.who}tuempresa.es
{r.service} · {r.year}
contraseña filtrada
{r.pwd.slice(0, 3)}{"●".repeat(Math.max(0, r.pwd.length - 3))}
⚠ sin cambiar
)}
▸ 0 cuentas con verificación en dos pasos
);
}
// ── 5. Network — before/after, all-flat vs segmented ─────────────────
function EvNetwork() {
return (
ANTES · TODO EN UNA RED
internet
router
{["Wifi invitados", "Cámaras", "Impresora", "Contabilidad", "Servidor ERP", "Nóminas"].map((d, i) =>
{d}
)}
⚠ 1 infectado = todos infectados
CON PEN · SEGMENTADO + FIREWALL
internet
FORTIGATE · firewall
PÚBLICA
Wifi · Cámaras
OFICINA
Impresoras · PCs
CRÍTICA
ERP · Nóminas
✓ Cada zona aislada
);
}
// ── 6. Backup — bad vs good cycle ─────────────────────────────────────
function EvBackup() {
return (
SIN PEN
Backup en la misma red
Última prueba: hace 14 meses
Restaurar = no se sabe si funciona
CON PEN · 3-2-1 VERIFICADO
3 copias · 2 sitios · 1 fuera
Restauración probada cada 30 días
Recuperas tu negocio en horas, no semanas
);
}
// ════════════════════════════════════════════════════════════════════
// Helpers
// ════════════════════════════════════════════════════════════════════
function sevClass(sev) {
const s = (sev || "").toLowerCase();
if (s.startsWith("crít") || s === "critical") return "crit";
if (s === "alto" || s === "high") return "warn";
return "info";
}
// ════════════════════════════════════════════════════════════════════
// SectionVuln
// ════════════════════════════════════════════════════════════════════
function SectionVuln({ copy }) {
return (
{copy.eyebrow}
{copy.title}
{copy.sub}
{copy.items.map((v, i) => {
const sev = sevClass(v.severity);
const flip = i % 2 === 1;
return (
0{i + 1}
● {v.severity}
{v.tag}
{v.title}
{v.body}
{v.stat}
{v.statLabel}
);
})}
);
}
// ════════════════════════════════════════════════════════════════════
// SectionSoluciones — card now has 3 layers: plain → benefit → caso
// ════════════════════════════════════════════════════════════════════
// ────────────────────────────────────────────────────────────────────
// Animated SVG illustrations for solution steps (vector schematics)
// ────────────────────────────────────────────────────────────────────
function VisualFirewall() {
return (
{/* Firewall barrier in center */}
{/* Glowing shield indicators */}
{/* Traffic flow particles */}
);
}
function VisualAgent() {
return (
{/* Laptop Keyboard / Base */}
{/* Laptop Screen */}
{/* Shield inside Screen */}
{/* Radar pulse lines from screen */}
);
}
function VisualRadar() {
return (
{/* Radar rings */}
{/* Crosshairs */}
{/* Radar Sweep line */}
{/* Blinking target nodes */}
);
}
function VisualPhishing() {
return (
{/* Valid Card (Verified User) */}
{/* Spoofed Card (Blocked Impostor) */}
);
}
function VisualVPN() {
return (
{/* Remote Laptop Outline */}
{/* Secure Enterprise Cloud Database */}
{/* Tunnel Pipe line */}
);
}
function VisualBackup() {
return (
{/* Main Server Cylinder (Center) */}
{/* Backup Dest 1: Local Copy (Top Left) */}
{/* Backup Dest 2: External Copy (Bottom Left) */}
{/* Backup Dest 3: Cloud Copy (Right) */}
{/* Sync path arrows */}
);
}
function SolucionVisual({ index }) {
switch (index) {
case 0: return ;
case 1: return ;
case 2: return ;
case 3: return ;
case 4: return ;
case 5: return ;
default: return null;
}
}
// ════════════════════════════════════════════════════════════════════
// SectionSoluciones — card now has 3 layers: plain → benefit → caso
// ════════════════════════════════════════════════════════════════════
function SectionSoluciones({ copy }) {
const [activeIndex, setActiveIndex] = useStateV(0);
const isEn = copy.eyebrow.toLowerCase().includes("what");
const stepLabels = isEn
? ["Network", "Endpoints", "Support", "Identity", "Access", "Backups"]
: ["Red", "Equipos", "Soporte", "Identidad", "Accesos", "Respaldos"];
const handlePrev = () => {
setActiveIndex((prev) => (prev > 0 ? prev - 1 : 5));
};
const handleNext = () => {
setActiveIndex((prev) => (prev < 5 ? prev + 1 : 0));
};
const activeItem = copy.items[activeIndex];
return (
{copy.eyebrow}
{copy.title}
{copy.sub}
{/* 1. Stepper / Sequence Timeline */}
{copy.items.map((item, idx) => {
const isActive = idx === activeIndex;
const isCompleted = idx < activeIndex;
return (
setActiveIndex(idx)}
>
{idx + 1}
{stepLabels[idx]}
);
})}
{/* 2. Main Showcase Panel */}
{/* Left Column: Core Identity, Benefit, and Tech Features */}
{activeItem.cat}
0{activeIndex + 1} / 06
{activeItem.name}
{activeItem.model}
{activeItem.plain}
›
{activeItem.benefit}
CARACTERÍSTICAS CLAVE
{activeItem.features.map((f, j) => (
▸
{f}
))}
{/* Right Column: Illustration, Case Report & Specs */}
⚡
CASO REAL / IMPACTO
"{activeItem.caso}"
RENDIMIENTO
{activeItem.spec.l1}
INTEGRACIÓN
{activeItem.spec.l2}
{/* 3. Navigation Controls */}
◀ {isEn ? "Prev" : "Anterior"}
{copy.items.map((_, idx) => (
setActiveIndex(idx)}
/>
))}
{activeIndex === 5 ? (isEn ? "Restart" : "Reiniciar") : (isEn ? "Next" : "Siguiente")} ▶
{/* Partners Strip */}
{copy.partnerStrip.label}
{(copy.partnerStrip.items || (copy.partnerStrip.groups ? copy.partnerStrip.groups.flatMap(g => g.items || []) : [])).map((p, i) =>
{p}
)}
);
}
Object.assign(window, { SectionVuln, SectionSoluciones });