Files
wevads-platform/public/weval-ssh.php
2026-04-07 03:04:16 +02:00

391 lines
19 KiB
PHP

<?php
session_start();
$servers = [
'weval-app' => ['name' => 'WEVAL Marketing', 'ip' => '95.216.167.89', 'user' => 'root', 'icon' => '📧', 'color' => '#22d3ee'],
'tracking' => ['name' => 'WEVAL Tracking', 'ip' => '151.80.235.110', 'user' => 'ubuntu', 'icon' => '📊', 'color' => '#a855f7'],
'consulting' => ['name' => 'WEVAL Consulting', 'ip' => '204.168.152.13', 'user' => 'root', 'icon' => '💼', 'color' => '#22c55e']
];
$currentServer = $_GET['server'] ?? 'weval-app';
$server = $servers[$currentServer] ?? $servers['weval-app'];
?>
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<title>WEVAL SSH — <?= $server['name'] ?></title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
:root{--bg:#0a0a0f;--s:#12121a;--s2:#1a1a2e;--b:#2a2a3e;--t:#e2e8f0;--d:#94a3b8;--cy:#22d3ee;--gn:#22c55e;--rd:#ef4444;--am:#eab308;--pu:#a855f7}
body{font-family:'DM Sans',sans-serif;background:var(--bg);color:var(--t);display:flex;height:100vh;overflow:hidden}
.sidebar{width:260px;background:var(--s);border-right:1px solid var(--b);padding:16px;overflow-y:auto;flex-shrink:0}
.sidebar h2{color:var(--cy);font-size:16px;margin-bottom:4px;display:flex;align-items:center;gap:8px}
.sidebar small{color:var(--d);font-size:11px}
.section-title{color:var(--d);font-size:10px;text-transform:uppercase;letter-spacing:1px;margin:20px 0 8px;padding-bottom:4px;border-bottom:1px solid var(--b)}
.server-item{padding:10px 12px;border-radius:8px;cursor:pointer;margin-bottom:4px;display:flex;align-items:center;gap:10px;transition:all .2s}
.server-item:hover{background:var(--s2)}
.server-item.active{background:var(--cy);color:#000}
.server-item .dot{width:8px;height:8px;border-radius:50%;background:var(--gn)}
.quick-cmd{padding:6px 10px;border-radius:6px;cursor:pointer;font-size:12px;color:var(--d);transition:all .2s}
.quick-cmd:hover{background:var(--s2);color:var(--t)}
.main{flex:1;display:flex;flex-direction:column}
.topbar{background:var(--s);border-bottom:1px solid var(--b);padding:10px 20px;display:flex;justify-content:space-between;align-items:center}
.topbar .title{font-family:'JetBrains Mono',monospace;color:var(--cy);font-size:13px}
.topbar .info{color:var(--d);font-size:11px}
.tabs{display:flex;gap:0;background:var(--s);border-bottom:1px solid var(--b)}
.tab{padding:10px 20px;cursor:pointer;font-size:12px;font-weight:600;color:var(--d);border-bottom:2px solid transparent;transition:all .2s}
.tab:hover{color:var(--t)}
.tab.active{color:var(--cy);border-color:var(--cy)}
.terminal-wrap{flex:1;overflow:hidden;display:flex;flex-direction:column}
.terminal{flex:1;overflow-y:auto;padding:16px;font-family:'JetBrains Mono',monospace;font-size:13px;line-height:1.6}
.terminal-line{padding:2px 0}
.terminal-line.system{color:var(--d)}
.terminal-line.error{color:var(--rd)}
.terminal-line.success{color:var(--gn)}
.terminal-line.hamid{color:var(--cy)}
.prompt-line{padding:8px 16px;background:var(--s);border-top:1px solid var(--b);display:flex;gap:8px;align-items:center}
.prompt-label{font-family:'JetBrains Mono',monospace;font-size:12px;color:var(--gn);white-space:nowrap}
.prompt-input{flex:1;background:transparent;border:none;color:var(--t);font-family:'JetBrains Mono',monospace;font-size:13px;outline:none}
.run-btn{background:var(--cy);color:#000;border:none;padding:6px 16px;border-radius:6px;font-weight:700;cursor:pointer;font-size:12px}
.run-btn:hover{opacity:.8}
.status-bar{background:var(--s);border-top:1px solid var(--b);padding:6px 16px;display:flex;gap:20px;font-size:11px;color:var(--d)}
.status-bar .dot{display:inline-block;width:6px;height:6px;border-radius:50%;margin-right:4px}
.chat-msg{margin:8px 0;padding:10px 14px;border-radius:10px;max-width:80%;font-size:13px;line-height:1.5}
.chat-msg.user{background:var(--s2);margin-left:auto;border-bottom-right-radius:2px}
.chat-msg.sentinel{background:rgba(34,211,238,.08);border:1px solid rgba(34,211,238,.15);border-bottom-left-radius:2px}
.chat-msg .tag{font-size:10px;color:var(--d);margin-bottom:4px}
.chat-msg pre{font-family:'JetBrains Mono',monospace;font-size:11px;background:var(--bg);padding:8px;border-radius:4px;margin-top:6px;overflow-x:auto;white-space:pre-wrap}
.hidden{display:none!important}
</style>
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;700&family=DM+Sans:wght@400;500;600;700&display=swap" rel="stylesheet">
</head>
<body>
<div class="sidebar">
<h2>🖥️ WEVAL SSH</h2>
<small>Terminal Web sécurisé</small>
<div class="section-title">Serveurs</div>
<?php foreach($servers as $key => $srv): ?>
<div class="server-item <?= $key === $currentServer ? 'active' : '' ?>" onclick="location.href='?server=<?= $key ?>'">
<span><?= $srv['icon'] ?></span>
<div><div style="font-size:13px;font-weight:600"><?= $srv['name'] ?></div><div style="font-size:10px;color:<?= $key === $currentServer ? '#000' : 'var(--d)' ?>"><?= $srv['ip'] ?></div></div>
<div class="dot" style="margin-left:auto"></div>
</div>
<?php endforeach; ?>
<div class="section-title">Commandes rapides</div>
<div class="quick-cmd" onclick="execCmd('htop')">📊 System Status</div>
<div class="quick-cmd" onclick="execCmd('systemctl status apache2')">🌐 Apache Status</div>
<div class="quick-cmd" onclick="execCmd('df -h')">💾 Disk Usage</div>
<div class="quick-cmd" onclick="execCmd('free -h')">🧠 Memory</div>
<div class="quick-cmd" onclick="execCmd('netstat -tlnp')">🔌 Ports</div>
<div class="quick-cmd" onclick="execCmd('ps aux --sort=-%mem | head -20')">📋 Processes</div>
<div class="quick-cmd" onclick="execCmd('tail -50 /var/log/syslog')">📝 Syslog</div>
<div class="section-title">Sentinel</div>
<div class="quick-cmd" onclick="sentinelCmd('scan')">🛡️ Lancer Scan</div>
<div class="quick-cmd" onclick="sentinelCmd('status')">📊 Status Sentinel</div>
</div>
<div class="main">
<div class="topbar">
<div class="title"><?= $server['user'] ?>@<?= $server['name'] ?> — <?= $server['ip'] ?></div>
<div class="info">
<span>Uptime: <span id="uptime">--</span></span> ·
<span>Load: <span id="load">--</span></span>
</div>
</div>
<div class="tabs">
<div class="tab active" onclick="switchTab('terminal')">💻 Terminal</div>
<div class="tab" onclick="switchTab('sentinel')">🛡️ Sentinel IA</div>
</div>
<!-- Terminal Tab -->
<div class="terminal-wrap" id="tab-terminal">
<div class="terminal" id="terminal">
<div class="terminal-line system">Connected to: <span style="color:var(--cy)"><?= $server['name'] ?></span> (<?= $server['ip'] ?>)</div>
<div class="terminal-line system">Type 'help' for available commands.</div>
<div class="terminal-line system">────────────────────────────</div>
</div>
<div class="prompt-line">
<span class="prompt-label"><?= $server['user'] ?>@WEVAL:~$</span>
<input type="text" class="prompt-input" id="cmdInput" placeholder="Enter command..." autofocus autocomplete="off">
<button class="run-btn" onclick="execCmd()">Run</button>
</div>
</div>
<!-- Sentinel Chat Tab -->
<div class="terminal-wrap hidden" id="tab-sentinel">
<div class="terminal" id="sentinelChat">
<div class="chat-msg sentinel">
<div class="tag">🛡️ SENTINEL</div>
Bonjour ! Je suis <b>Weval Mind Sentinel</b>. Je scanne, détecte et répare les problèmes d'infrastructure automatiquement.<br><br>
Commandes disponibles :<br>
• <code>scan</code> — Lancer un scan complet<br>
• <code>status</code> — État actuel du système<br>
• <code>patterns</code> — Patterns connus<br>
• <code>fixes</code> — Dernières réparations<br>
• <code>check [fichier]</code> — Vérifier un fichier spécifique<br>
• Ou posez une question en langage naturel
</div>
</div>
<div class="prompt-line">
<span class="prompt-label" style="color:var(--cy)">🛡️ sentinel&gt;</span>
<input type="text" class="prompt-input" id="sentinelInput" placeholder="Parlez au Sentinel..." autocomplete="off">
<button class="run-btn" style="background:var(--pu)" onclick="sendSentinel()">Envoyer</button>
</div>
</div>
<div class="status-bar">
<span><span class="dot" style="background:var(--gn)"></span> Connected</span>
<span>Server: <?= $server['ip'] ?></span>
<span>User: <?= $server['user'] ?></span>
</div>
</div>
<script>
// ═══════════════════════════════════════════════════
// TAB SWITCHING
// ═══════════════════════════════════════════════════
function switchTab(tab) {
document.querySelectorAll('.tab').forEach(function(t) { t.classList.remove('active'); });
document.querySelectorAll('.terminal-wrap').forEach(function(w) { w.classList.add('hidden'); });
document.getElementById('tab-' + tab).classList.remove('hidden');
event.target.classList.add('active');
if (tab === 'terminal') document.getElementById('cmdInput').focus();
else document.getElementById('sentinelInput').focus();
}
// ═══════════════════════════════════════════════════
// TERMINAL MODE
// ═══════════════════════════════════════════════════
var cmdHistory = [];
var histIdx = -1;
document.getElementById('cmdInput').addEventListener('keydown', function(e) {
if (e.key === 'Enter') execCmd();
else if (e.key === 'ArrowUp') { e.preventDefault(); navHistory(1); }
else if (e.key === 'ArrowDown') { e.preventDefault(); navHistory(-1); }
});
function navHistory(dir) {
if (cmdHistory.length === 0) return;
histIdx = Math.max(-1, Math.min(cmdHistory.length - 1, histIdx + dir));
document.getElementById('cmdInput').value = histIdx >= 0 ? cmdHistory[cmdHistory.length - 1 - histIdx] : '';
}
function addLine(text, type) {
var div = document.createElement('div');
div.className = 'terminal-line ' + (type || '');
div.innerHTML = text;
var term = document.getElementById('terminal');
term.appendChild(div);
term.scrollTop = term.scrollHeight;
}
function execCmd(preset) {
var input = document.getElementById('cmdInput');
var cmd = preset || input.value.trim();
if (!cmd) return;
if (!preset) { input.value = ''; }
cmdHistory.push(cmd);
histIdx = -1;
var time = new Date().toLocaleTimeString('fr-FR');
addLine('<span style="color:var(--gn)"><?= $server['user'] ?>@WEVAL:~$</span> ' + cmd + ' <span style="color:var(--d);font-size:10px">' + time + '</span>');
if (cmd === 'clear') { document.getElementById('terminal').innerHTML = ''; return; }
if (cmd === 'help') { addLine('Commands: clear, help, history, + any Linux command', 'system'); return; }
addLine('⏳ Executing...', 'system');
fetch('/weval-ssh-api.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ command: cmd, server: '<?= $currentServer ?>' })
})
.then(function(r) { return r.json(); })
.then(function(data) {
var term = document.getElementById('terminal');
if (term.lastChild) term.removeChild(term.lastChild);
if (data.error) {
addLine(data.error, 'error');
} else {
var output = data.output || '(no output)';
output.split('\n').forEach(function(line) {
addLine(line, data.exit_code === 0 ? '' : 'error');
});
addLine('[' + (data.duration || '0ms') + ', exit: ' + (data.exit_code || 0) + ']', 'system');
}
})
.catch(function(e) {
var term = document.getElementById('terminal');
if (term.lastChild) term.removeChild(term.lastChild);
addLine('Connection error: ' + e.message, 'error');
});
}
// ═══════════════════════════════════════════════════
// SENTINEL CHAT MODE
// ═══════════════════════════════════════════════════
document.getElementById('sentinelInput').addEventListener('keydown', function(e) {
if (e.key === 'Enter') sendSentinel();
});
function addChat(text, type) {
var div = document.createElement('div');
div.className = 'chat-msg ' + type;
div.innerHTML = (type === 'sentinel' ? '<div class="tag">🛡️ SENTINEL</div>' : '<div class="tag">👤 Vous</div>') + text;
var chat = document.getElementById('sentinelChat');
chat.appendChild(div);
chat.scrollTop = chat.scrollHeight;
}
function sentinelCmd(action) {
switchTab('sentinel');
setTimeout(function() {
document.getElementById('sentinelInput').value = action;
sendSentinel();
}, 100);
}
function sendSentinel() {
var input = document.getElementById('sentinelInput');
var msg = input.value.trim();
if (!msg) return;
input.value = '';
addChat(msg, 'user');
var cmd = msg.toLowerCase();
if (cmd === 'scan') {
addChat('⏳ Scan en cours... Analyse de toute l\'infrastructure...', 'sentinel');
fetch('/api/sentinel-engine.php?action=scan&fix=1')
.then(function(r) { return r.json(); })
.then(function(d) {
var html = '<b>Scan terminé !</b><br><br>';
html += '📊 Score: <b style="color:' + (d.score >= 95 ? 'var(--gn)' : 'var(--am)') + '">' + d.score + '%</b><br>';
html += '📁 Fichiers scannés: <b>' + d.total_files + '</b><br>';
html += '⚠️ Issues détectées: <b>' + d.issues_found + '</b><br>';
html += '✅ Auto-réparées: <b>' + d.issues_fixed + '</b><br>';
html += '⏱️ Durée: ' + d.duration_ms + 'ms<br>';
if (d.issues && d.issues.length > 0) {
html += '<br><b>Issues:</b><pre>';
d.issues.forEach(function(i) { html += i.type + ': ' + i.file + '\n'; });
html += '</pre>';
} else {
html += '<br>✅ <b style="color:var(--gn)">Infrastructure saine !</b>';
}
addChat(html, 'sentinel');
})
.catch(function(e) { addChat('❌ Erreur: ' + e.message, 'sentinel'); });
}
else if (cmd === 'status') {
fetch('/api/sentinel-engine.php?action=status')
.then(function(r) { return r.json(); })
.then(function(d) {
var html = '<b>État Sentinel</b><br><br>';
html += '🔄 Total scans: <b>' + d.total_scans + '</b><br>';
html += '🔧 Total fixes: <b>' + d.total_fixes + '</b><br>';
html += '🧠 Patterns connus: <b>' + (d.patterns ? d.patterns.length : 0) + '</b><br>';
if (d.last_scan) {
html += '<br>Dernier scan: ' + new Date(d.last_scan.scan_date).toLocaleString('fr-FR');
html += '<br>Score: <b>' + d.last_scan.score + '%</b>';
}
addChat(html, 'sentinel');
})
.catch(function(e) { addChat('❌ Erreur: ' + e.message, 'sentinel'); });
}
else if (cmd === 'patterns') {
fetch('/api/sentinel-engine.php?action=patterns')
.then(function(r) { return r.json(); })
.then(function(d) {
var html = '<b>Patterns connus (' + d.patterns.length + ')</b><pre>';
d.patterns.forEach(function(p) {
html += p.pattern_name + ' [' + p.severity + '] → ' + p.times_detected + ' détections\n';
});
html += '</pre>';
addChat(html, 'sentinel');
})
.catch(function(e) { addChat('❌ Erreur: ' + e.message, 'sentinel'); });
}
else if (cmd === 'fixes') {
fetch('/api/sentinel-engine.php?action=fixes&limit=10')
.then(function(r) { return r.json(); })
.then(function(d) {
if (!d.fixes || d.fixes.length === 0) { addChat('Aucune réparation enregistrée.', 'sentinel'); return; }
var html = '<b>Dernières réparations</b><pre>';
d.fixes.forEach(function(f) {
html += new Date(f.fix_date).toLocaleString('fr-FR') + '\n ' + f.issue_type + ': ' + f.file_path.split('/').pop() + '\n → ' + f.fix_applied + '\n\n';
});
html += '</pre>';
addChat(html, 'sentinel');
})
.catch(function(e) { addChat('❌ Erreur: ' + e.message, 'sentinel'); });
}
else if (cmd.startsWith('check ')) {
var file = cmd.substring(6);
addChat('⏳ Vérification de <code>' + file + '</code>...', 'sentinel');
fetch('/weval-ssh-api.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ command: 'php -l ' + file + ' 2>&1; echo "---"; head -5 ' + file, server: 'weval-app' })
})
.then(function(r) { return r.json(); })
.then(function(d) { addChat('<pre>' + (d.output || 'No output') + '</pre>', 'sentinel'); })
.catch(function(e) { addChat('❌ ' + e.message, 'sentinel'); });
}
else {
// Natural language → forward to HAMID
addChat('⏳ Analyse en cours...', 'sentinel');
fetch('/hamid-api.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ message: 'En tant que Sentinel infrastructure, réponds à: ' + msg, provider: 'Cerebras' })
})
.then(function(r) { return r.json(); })
.then(function(d) {
var chat = document.getElementById('sentinelChat');
if (chat.lastChild) chat.removeChild(chat.lastChild);
addChat(d.response || d.error || 'Pas de réponse', 'sentinel');
})
.catch(function(e) {
var chat = document.getElementById('sentinelChat');
if (chat.lastChild) chat.removeChild(chat.lastChild);
addChat('❌ ' + e.message, 'sentinel');
});
}
}
// ═══════════════════════════════════════════════════
// AUTO-LOAD STATS
// ═══════════════════════════════════════════════════
function loadStats() {
fetch('/weval-ssh-api.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ command: 'uptime', server: '<?= $currentServer ?>' })
})
.then(function(r) { return r.json(); })
.then(function(data) {
if (data.output) {
var m = data.output.match(/up\s+([^,]+)/);
if (m) { var el = document.getElementById('uptime'); if (el) el.textContent = m[1].trim(); }
var lm = data.output.match(/load average:\s*([0-9.]+)/);
if (lm) { var el2 = document.getElementById('load'); if (el2) el2.textContent = lm[1]; }
}
})
.catch(function() {});
}
loadStats();
setInterval(loadStats, 60000);
</script>
</body>
</html>