Files
html/vnc-picker.html

365 lines
21 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>WEVIA Cyber Command — Profile Picker</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Cormorant+Garamond:wght@300;400;500;700&family=JetBrains+Mono:wght@300;400;500;700&display=swap" rel="stylesheet">
<style>
:root{
--bg:#08080c;--panel:rgba(18,18,26,0.55);--panel-hover:rgba(28,28,40,0.75);
--border:rgba(255,255,255,0.06);--border-hover:rgba(246,213,114,0.4);
--ink:#ebe6d8;--ink-dim:#9a9384;--ink-faint:#5a5650;
--gold:#f6d572;--gold-deep:#b8923c;--coral:#ff6b5e;--mint:#7fffd4;--azure:#8ecfff;
--font-display:'Cormorant Garamond',serif;--font-mono:'JetBrains Mono',ui-monospace,monospace;
--ease:cubic-bezier(.23,1,.32,1);--ease-out:cubic-bezier(.16,1,.3,1);
}
*{margin:0;padding:0;box-sizing:border-box}
html,body{background:var(--bg);color:var(--ink);font-family:var(--font-mono);min-height:100vh;overflow-x:hidden;font-weight:300;letter-spacing:.02em}
/* Atmosphere - gradient mesh background */
body::before{
content:"";position:fixed;inset:0;z-index:0;pointer-events:none;
background:
radial-gradient(ellipse 80% 60% at 20% 10%,rgba(246,213,114,0.08) 0%,transparent 55%),
radial-gradient(ellipse 60% 80% at 85% 90%,rgba(142,207,255,0.06) 0%,transparent 55%),
radial-gradient(ellipse 50% 40% at 50% 50%,rgba(127,255,212,0.03) 0%,transparent 60%);
}
/* Noise texture overlay */
body::after{
content:"";position:fixed;inset:0;z-index:0;pointer-events:none;opacity:0.035;
background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)'/%3E%3C/svg%3E");
}
main{position:relative;z-index:1;min-height:100vh;padding:48px 56px 96px;max-width:1680px;margin:0 auto}
/* Header - editorial premium */
.masthead{display:grid;grid-template-columns:1fr auto;align-items:end;gap:40px;margin-bottom:56px;padding-bottom:32px;border-bottom:1px solid var(--border)}
.eyebrow{display:flex;align-items:center;gap:14px;color:var(--gold);font-size:10px;font-weight:500;letter-spacing:.42em;text-transform:uppercase;margin-bottom:18px}
.eyebrow::before{content:"";width:28px;height:1px;background:var(--gold)}
.eyebrow .live-dot{width:6px;height:6px;border-radius:50%;background:var(--mint);box-shadow:0 0 12px var(--mint);animation:pulse 2s ease infinite}
@keyframes pulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.4;transform:scale(1.2)}}
h1{font-family:var(--font-display);font-weight:300;font-size:clamp(48px,6vw,88px);line-height:.94;letter-spacing:-.03em;color:var(--ink)}
h1 em{font-style:italic;font-weight:400;color:var(--gold);position:relative}
h1 em::after{content:"";position:absolute;left:0;bottom:.08em;width:100%;height:1px;background:var(--gold);opacity:.5}
.subtitle{max-width:520px;margin-top:24px;font-size:13px;line-height:1.8;color:var(--ink-dim);font-weight:300}
.stats{display:flex;gap:40px;align-items:flex-start}
.stat{text-align:right}
.stat-value{font-family:var(--font-display);font-size:52px;font-weight:300;line-height:1;color:var(--gold);letter-spacing:-.02em}
.stat-label{font-size:9px;letter-spacing:.32em;text-transform:uppercase;color:var(--ink-faint);margin-top:8px}
/* Command bar */
.command-bar{display:flex;align-items:center;gap:12px;padding:14px 18px;background:var(--panel);backdrop-filter:blur(20px);border:1px solid var(--border);border-radius:2px;margin-bottom:40px;font-size:11px}
.cb-prompt{color:var(--gold);font-weight:500;letter-spacing:.12em}
.cb-path{color:var(--ink-dim);flex:1}
.cb-actions{display:flex;gap:4px}
.cb-btn{padding:7px 14px;background:transparent;border:1px solid var(--border);color:var(--ink-dim);font-family:var(--font-mono);font-size:10px;letter-spacing:.12em;text-transform:uppercase;cursor:pointer;text-decoration:none;transition:all .3s var(--ease);font-weight:400}
.cb-btn:hover{background:var(--panel-hover);border-color:var(--border-hover);color:var(--gold)}
.cb-btn.primary{background:var(--gold);color:#0a0a0f;border-color:var(--gold);font-weight:600}
.cb-btn.primary:hover{background:var(--ink);border-color:var(--ink)}
/* Instructions - editorial style */
.briefing{display:grid;grid-template-columns:auto 1fr auto;gap:32px;margin-bottom:56px;padding:28px 32px;background:linear-gradient(135deg,rgba(246,213,114,0.04) 0%,transparent 60%);border:1px solid var(--border);border-left:2px solid var(--gold);border-radius:2px;position:relative;overflow:hidden}
.briefing::before{content:"BRIEFING";position:absolute;top:12px;right:16px;font-size:8px;letter-spacing:.42em;color:var(--gold);opacity:.4;font-weight:600}
.briefing-num{font-family:var(--font-display);font-size:88px;font-weight:300;line-height:1;color:var(--gold);opacity:.2}
.briefing-steps{display:flex;flex-direction:column;gap:10px;padding:8px 0}
.briefing-step{display:flex;align-items:baseline;gap:16px;font-size:12px;line-height:1.6}
.briefing-step-n{color:var(--gold);font-weight:500;min-width:24px;font-variant-numeric:tabular-nums}
.briefing-step span{color:var(--ink-dim)}
.briefing-step code{color:var(--gold);background:rgba(246,213,114,0.08);padding:2px 6px;border-radius:2px;font-size:11px}
.briefing-secret{align-self:flex-end;display:flex;flex-direction:column;gap:6px;text-align:right}
.briefing-secret-label{font-size:9px;letter-spacing:.32em;text-transform:uppercase;color:var(--ink-faint)}
.briefing-secret-value{font-size:13px;color:var(--gold);font-weight:500;letter-spacing:.04em}
/* Cards grid */
.section-label{display:flex;align-items:center;gap:16px;font-size:10px;letter-spacing:.42em;text-transform:uppercase;color:var(--ink-faint);margin-bottom:24px;font-weight:500}
.section-label::before,.section-label::after{content:"";flex:1;height:1px;background:var(--border)}
.section-label span{color:var(--gold)}
.profiles{display:grid;grid-template-columns:repeat(auto-fill,minmax(340px,1fr));gap:20px}
.profile-card{position:relative;padding:26px 28px 22px;background:var(--panel);backdrop-filter:blur(20px);border:1px solid var(--border);border-radius:3px;cursor:pointer;transition:all .5s var(--ease);overflow:hidden;opacity:0;animation:slideUp .9s var(--ease) forwards}
.profile-card:nth-child(1){animation-delay:.05s}
.profile-card:nth-child(2){animation-delay:.1s}
.profile-card:nth-child(3){animation-delay:.15s}
.profile-card:nth-child(4){animation-delay:.2s}
.profile-card:nth-child(5){animation-delay:.25s}
.profile-card:nth-child(6){animation-delay:.3s}
.profile-card:nth-child(7){animation-delay:.35s}
.profile-card:nth-child(8){animation-delay:.4s}
@keyframes slideUp{from{opacity:0;transform:translateY(28px)}to{opacity:1;transform:translateY(0)}}
.profile-card::before{content:"";position:absolute;inset:0;background:radial-gradient(ellipse 80% 60% at 50% 0%,rgba(246,213,114,0.12) 0%,transparent 70%);opacity:0;transition:opacity .6s var(--ease);pointer-events:none}
.profile-card::after{content:"";position:absolute;top:0;left:0;right:0;height:1px;background:linear-gradient(90deg,transparent 0%,var(--gold) 50%,transparent 100%);opacity:0;transition:opacity .4s var(--ease)}
.profile-card:hover{border-color:var(--border-hover);background:var(--panel-hover);transform:translateY(-3px)}
.profile-card:hover::before{opacity:1}
.profile-card:hover::after{opacity:.6}
.pc-top{display:flex;align-items:center;justify-content:space-between;margin-bottom:22px;position:relative}
.pc-monogram{font-family:var(--font-display);font-size:44px;font-weight:400;line-height:.85;color:var(--gold);letter-spacing:-.03em;font-style:italic}
.pc-index{font-size:9px;letter-spacing:.32em;color:var(--ink-faint);font-weight:500}
.pc-name{font-family:var(--font-display);font-size:26px;font-weight:400;letter-spacing:-.01em;color:var(--ink);line-height:1.1;margin-bottom:4px}
.pc-domain{font-size:11px;color:var(--ink-dim);letter-spacing:.04em;margin-bottom:18px;word-break:break-all}
.pc-status{display:flex;align-items:center;gap:10px;padding:10px 14px;margin:0 -4px 18px;background:rgba(255,255,255,0.02);border:1px solid var(--border);border-radius:2px;font-size:10px;letter-spacing:.12em;text-transform:uppercase}
.pc-status-dot{width:6px;height:6px;border-radius:50%;background:var(--ink-faint);flex-shrink:0;transition:all .3s var(--ease)}
.pc-status-dot.logged{background:var(--mint);box-shadow:0 0 8px var(--mint);animation:pulse 2.4s ease infinite}
.pc-status-dot.running{background:var(--gold);box-shadow:0 0 8px var(--gold);animation:pulse 1.8s ease infinite}
.pc-status-dot.offline{background:var(--coral);opacity:.4}
.pc-status-label{color:var(--ink-dim);flex:1}
.pc-status-label.ok{color:var(--mint)}
.pc-status-label.warn{color:var(--gold)}
.pc-status-meta{color:var(--ink-faint);font-family:var(--font-mono);font-size:10px;letter-spacing:0}
.pc-path{font-size:10px;color:var(--ink-faint);font-family:var(--font-mono);padding:8px 10px;background:rgba(0,0,0,0.25);border:1px solid var(--border);border-radius:2px;margin-bottom:18px;letter-spacing:-.01em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.pc-actions{display:flex;gap:6px}
.pc-btn{flex:1;padding:11px 14px;background:transparent;border:1px solid var(--border);color:var(--ink-dim);font-family:var(--font-mono);font-size:10px;letter-spacing:.14em;text-transform:uppercase;cursor:pointer;transition:all .3s var(--ease);font-weight:500;text-decoration:none;text-align:center;border-radius:2px}
.pc-btn:hover{background:rgba(246,213,114,0.08);border-color:var(--gold);color:var(--gold)}
.pc-btn.primary{background:var(--gold);color:#0a0a0f;border-color:var(--gold);font-weight:600}
.pc-btn.primary:hover{background:var(--ink);border-color:var(--ink)}
/* Toast */
.toast-stack{position:fixed;bottom:32px;left:32px;z-index:9999;display:flex;flex-direction:column-reverse;gap:10px;pointer-events:none;max-width:380px}
.toast{min-width:320px;padding:16px 20px;background:rgba(18,18,26,0.95);backdrop-filter:blur(24px);border:1px solid var(--border);border-left:2px solid var(--gold);border-radius:2px;font-size:12px;color:var(--ink-dim);box-shadow:0 20px 40px -12px rgba(0,0,0,0.6);pointer-events:auto;animation:toastIn .5s var(--ease) forwards}
.toast-title{color:var(--gold);font-size:10px;letter-spacing:.28em;text-transform:uppercase;margin-bottom:6px;font-weight:500}
.toast.success{border-left-color:var(--mint)}.toast.success .toast-title{color:var(--mint)}
.toast.error{border-left-color:var(--coral)}.toast.error .toast-title{color:var(--coral)}
@keyframes toastIn{from{opacity:0;transform:translateX(-24px)}to{opacity:1;transform:translateX(0)}}
/* Footer */
footer{margin-top:80px;padding-top:32px;border-top:1px solid var(--border);display:flex;align-items:center;justify-content:space-between;font-size:10px;letter-spacing:.12em;color:var(--ink-faint)}
footer a{color:var(--ink-dim);text-decoration:none;transition:color .3s var(--ease)}
footer a:hover{color:var(--gold)}
@media(max-width:900px){
main{padding:32px 24px 72px}
.masthead{grid-template-columns:1fr;gap:32px}
.stats{justify-content:flex-start}
.briefing{grid-template-columns:1fr;padding:24px}
.briefing-num{display:none}
}
</style>
<!-- DOCTRINE-60-UX-ENRICH direct-inject-20260424-143919 -->
<style id="doctrine60-ux-direct">
/* DOCTRINE-60-UX-ENRICH injected-direct */
body::before {
content: '';
position: fixed;
top: 0; left: 0; width: 100vw; height: 100vh;
background: radial-gradient(circle at 50% 50%, rgba(100,180,255,0.08), transparent 60%);
pointer-events: none;
z-index: -1;
}
.card, .kpi, .panel, .btn {
transition: all 0.3s cubic-bezier(0.2,0,0.1,1);
}
.card:hover, .kpi:hover, .panel:hover {
box-shadow: 0 4px 20px rgba(100,180,255,0.2);
border-color: rgba(100,180,255,0.5);
}
@keyframes pulseD60 {
0%,100% { opacity: 1; transform: scale(1); }
50% { opacity: 0.7; transform: scale(1.05); }
}
.pulse, .live-indicator, .active, .online {
animation: pulseD60 3s ease-in-out infinite;
}
.modal, .chat, .speech, .overlay {
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
}
.enter-stagger {
animation: enterStagD60 0.5s cubic-bezier(0.2,0,0.1,1) forwards;
}
@keyframes enterStagD60 {
from { opacity: 0; transform: translateY(20px); }
to { opacity: 1; transform: translateY(0); }
}
</style>
</head>
<body>
<main>
<header class="masthead">
<div>
<div class="eyebrow"><span class="live-dot"></span> Doctrine 161 / 164 — Cyber Command Live</div>
<h1>Cyber <em>Profile</em><br>Picker</h1>
<p class="subtitle">Session interactive via noVNC pour étendre la souveraineté WEVIA aux 8 Web-IA gratuits. Login une fois — exploitation illimitée via Selenium CDP.</p>
</div>
<div class="stats">
<div class="stat"><div class="stat-value" id="stat-logged">0</div><div class="stat-label">Logged</div></div>
<div class="stat"><div class="stat-value" id="stat-running">0</div><div class="stat-label">Running</div></div>
<div class="stat"><div class="stat-value">8</div><div class="stat-label">Providers</div></div>
</div>
</header>
<div class="command-bar">
<span class="cb-prompt">wevia://</span>
<span class="cb-path">/cyber-profile-picker</span>
<div class="cb-actions">
<a class="cb-btn primary" href="/novnc/vnc.html" target="_blank">Open noVNC</a>
<a class="cb-btn" href="/web-ia-status.html">Dashboard</a>
<a class="cb-btn" href="/wevia-audit.html">Audit Trail</a>
<a class="cb-btn" href="javascript:location.reload()">Refresh</a>
</div>
</div>
<section class="briefing">
<div class="briefing-num">00</div>
<div class="briefing-steps">
<div class="briefing-step"><span class="briefing-step-n">01.</span><span>Sélectionne un profil ci-dessous — Chrome se lance dans le display virtuel du serveur avec <code>--remote-debugging-port</code> unique.</span></div>
<div class="briefing-step"><span class="briefing-step-n">02.</span><span>Clique "Open noVNC" pour projeter le bureau distant dans ton navigateur.</span></div>
<div class="briefing-step"><span class="briefing-step-n">03.</span><span>Login manuel (email, 2FA, etc.) — la session persiste dans <code>/var/lib/wevia-cyber-profiles/&lt;slug&gt;</code>.</span></div>
<div class="briefing-step"><span class="briefing-step-n">04.</span><span>WEVIA exploite la session via Selenium CDP attach — plus jamais de re-login.</span></div>
</div>
<div class="briefing-secret">
<div class="briefing-secret-label">VNC Password</div>
<div class="briefing-secret-value" id="vnc-pw">weviaVNC2026yac</div>
</div>
</section>
<div class="section-label"><span>Providers</span></div>
<div class="profiles" id="profiles-grid"></div>
<footer>
<div>WEVIA AUTONOMY — v1.7 / DOCTRINES 146164</div>
<div><a href="/wevia-audit.html">Audit Trail</a> · <a href="/web-ia-status.html">Live Status</a> · <a href="https://weval-consulting.com">weval-consulting.com</a></div>
</footer>
</main>
<div class="toast-stack" id="toast-stack"></div>
<script>
const PROVIDERS=[
{slug:'openai',name:'ChatGPT',mono:'C',domain:'chat.openai.com',cdp:9222},
{slug:'anthropic',name:'Claude.ai',mono:'A',domain:'claude.ai',cdp:9223},
{slug:'google',name:'Gemini',mono:'G',domain:'gemini.google.com',cdp:9224},
{slug:'deepseek',name:'DeepSeek',mono:'D',domain:'chat.deepseek.com',cdp:9225},
{slug:'mistral',name:'Mistral',mono:'M',domain:'chat.mistral.ai',cdp:9226},
{slug:'poe',name:'Poe',mono:'P',domain:'poe.com',cdp:9227},
{slug:'perplexity',name:'Perplexity',mono:'Px',domain:'www.perplexity.ai',cdp:9228},
{slug:'hf',name:'HuggingFace',mono:'H',domain:'huggingface.co',cdp:9229},
];
const state={};PROVIDERS.forEach(p=>state[p.slug]={running:false,logged:'unknown',cdp:null});
function toast(title,msg,kind){
const s=document.getElementById('toast-stack');
const t=document.createElement('div');
t.className='toast'+(kind?' '+kind:'');
t.innerHTML=`<div class="toast-title">${title}</div><div>${msg}</div>`;
s.appendChild(t);
setTimeout(()=>{t.style.opacity='0';t.style.transform='translateX(24px)';t.style.transition='all .4s';setTimeout(()=>t.remove(),400)},4800);
}
function render(){
const g=document.getElementById('profiles-grid');
g.innerHTML=PROVIDERS.map((p,i)=>{
const s=state[p.slug];
const dotCls=s.logged===true?'logged':s.running?'running':'offline';
const lbl=s.logged===true?'Session active':s.running?'Chrome running':'Not started';
const lblCls=s.logged===true?'ok':s.running?'warn':'';
const meta=s.cdp?`cdp :${s.cdp}`:s.running?'—':'—';
return `<article class="profile-card" data-slug="${p.slug}">
<div class="pc-top">
<div class="pc-monogram">${p.mono}</div>
<div class="pc-index">${String(i+1).padStart(2,'0')} / 08</div>
</div>
<div class="pc-name">${p.name}</div>
<div class="pc-domain">${p.domain}</div>
<div class="pc-status">
<div class="pc-status-dot ${dotCls}"></div>
<div class="pc-status-label ${lblCls}">${lbl}</div>
<div class="pc-status-meta">${meta}</div>
</div>
<div class="pc-path">/var/lib/wevia-cyber-profiles/${p.slug}</div>
<div class="pc-actions">
<button class="pc-btn primary" onclick="launch('${p.slug}')">Launch</button>
<a class="pc-btn" href="/novnc/vnc.html" target="_blank">noVNC</a>
</div>
</article>`;
}).join('');
const logged=Object.values(state).filter(s=>s.logged===true).length;
const running=Object.values(state).filter(s=>s.running).length;
document.getElementById('stat-logged').textContent=String(logged).padStart(2,'0');
document.getElementById('stat-running').textContent=String(running).padStart(2,'0');
}
async function launch(slug){
const prov=PROVIDERS.find(p=>p.slug===slug);
toast('Launching',`Chrome instance on profile ${prov.name}`);
try{
const r=await fetch('/api/wevia-autowire-trigger.php?action=chrome-launch&profile='+slug);
const d=await r.json();
if(d.ok&&d.result){
state[slug].running=true;
state[slug].cdp=d.result.cdp_port||prov.cdp;
toast('Online',`${prov.name} running · CDP :${state[slug].cdp}`,'success');
render();
setTimeout(()=>window.open('/novnc/vnc.html','_blank'),600);
}else{
toast('Failed',d.err||JSON.stringify(d).slice(0,120),'error');
}
}catch(e){toast('Error',e.message,'error')}
}
async function probeStatus(){
for(const p of PROVIDERS){
try{
const r=await fetch(`http://127.0.0.1:${p.cdp}/json/version`,{signal:AbortSignal.timeout(1500)}).catch(()=>null);
if(r&&r.ok){
state[p.slug].running=true;
state[p.slug].cdp=p.cdp;
}
}catch(e){}
}
render();
}
render();
// probeStatus() would be CORS-blocked from browser, so skip. Status updated on user action.
// Subtle cursor tilt on cards
document.addEventListener('mousemove',e=>{
document.querySelectorAll('.profile-card').forEach(c=>{
const r=c.getBoundingClientRect();
const inside=e.clientX>=r.left&&e.clientX<=r.right&&e.clientY>=r.top&&e.clientY<=r.bottom;
if(inside){
const x=(e.clientX-r.left)/r.width-.5;const y=(e.clientY-r.top)/r.height-.5;
c.style.transform=`translateY(-3px) perspective(800px) rotateX(${-y*2}deg) rotateY(${x*2}deg)`;
}else{c.style.transform=''}
});
},{passive:true});
// WAVE 308 - CDP status proxy polling (bypass CORS)
async function pollCDPStatusLive(){try{const r=await fetch('/api/cdp-status.php?cb='+Date.now());if(!r.ok)return;const d=await r.json();if(!d.providers)return;d.providers.forEach(p=>{const cards=document.querySelectorAll('.profile-card');cards.forEach(c=>{const t=c.querySelector('.pc-path');if(!t||!t.textContent.includes(p.slug))return;const dot=c.querySelector('.pc-status-dot');const lbl=c.querySelector('.pc-status-label');const meta=c.querySelector('.pc-status-meta');if(p.cdp_listening){if(dot){dot.classList.remove('offline');dot.classList.add('running');}if(lbl){lbl.textContent='CHROME RUNNING';lbl.classList.add('warn');}if(meta)meta.textContent='CDP :'+p.port;}else{if(dot){dot.classList.remove('running','logged');dot.classList.add('offline');}if(lbl){lbl.textContent='NOT STARTED';lbl.classList.remove('warn','ok');}if(meta)meta.textContent='—';}});});const topBadge=document.querySelector('.command-bar');if(topBadge){const sumEl=topBadge.querySelector('.cdp-sum')||(()=>{const s=document.createElement('span');s.className='cdp-sum';s.style.cssText='margin-left:auto;color:var(--mint);font-family:var(--font-mono);';topBadge.appendChild(s);return s;})();sumEl.textContent='CDP LIVE: '+d.summary.running+'/'+d.summary.total+' · '+d.summary.coverage_pct+'%';}}catch(e){console.warn('[CDP poll] err',e);}}
pollCDPStatusLive();setInterval(pollCDPStatusLive,5000);</script>
<!-- DOCTRINE-60-UX-JS --><script id="doctrine60-ux-js-direct">
// DOCTRINE-60-UX-JS staggered entrance
(function(){
if (!('IntersectionObserver' in window)) return;
const obs = new IntersectionObserver((entries) => {
entries.forEach((e, i) => {
if (e.isIntersecting) {
setTimeout(() => e.target.classList.add('enter-stagger'), i * 80);
obs.unobserve(e.target);
}
});
});
document.querySelectorAll('.card, .kpi, .panel').forEach(el => obs.observe(el));
})();
</script>
</body></html>