BastionGuard/webui/scan.php
specialworld83 f0f913a209 Release 2.0
2026-07-15 10:52:22 +02:00

117 lines
11 KiB
PHP

<?php
include 'auth.php';
require_once __DIR__ . '/includes/config_manager.php';
$page_title = bg_t('scan_realtime') . ' - BastionGuard WebUI';
$active_page = 'scan.php';
$settings = bg_config_read(bg_config_catalog()['scan_config']);
$scanCfg = is_array($settings['parsed'] ?? null) ? $settings['parsed'] : ['auto_scan_enabled'=>true];
$cloud = bg_config_read(bg_config_catalog()['cloud']);
$cloudParsed = is_array($cloud['parsed'] ?? null) ? $cloud['parsed'] : [];
$scannerRead = bg_config_read(bg_config_catalog()['scanner']);
$scannerParsed = is_array($scannerRead['parsed'] ?? null) ? $scannerRead['parsed'] : [];
$output = '';
$defaultWatch = [];
if (!empty($scannerParsed['scan_path'])) {
foreach (preg_split('/[;\r\n]+/', (string)$scannerParsed['scan_path']) as $p) { $p = trim($p); if ($p !== '') $defaultWatch[] = $p; }
}
if (!$defaultWatch) {
$du = bg_detect_desktop_user();
$rec = $du ? bg_user_record($du) : null;
$candidates = [];
if ($rec && !empty($rec['home'])) {
$home = rtrim($rec['home'], '/');
$candidates[] = $home . '/Downloads';
$candidates[] = $home . '/public_html';
$candidates[] = $home . '/www';
}
foreach (['/home','/var/www','/var/www/html','/srv/http','/srv/www','/tmp'] as $p0) $candidates[] = $p0;
foreach ($candidates as $p0) { if (is_dir($p0) && !in_array($p0, $defaultWatch, true)) $defaultWatch[] = $p0; }
if (!$defaultWatch) $defaultWatch[] = '/home';
}
$monitorPaths = bg_read_json('scan_inotify_paths.json', ['paths'=>$defaultWatch]);
if (empty($monitorPaths['paths']) || !is_array($monitorPaths['paths'])) $monitorPaths['paths'] = $defaultWatch;
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
csrf_validate();
$action = $_POST['action'] ?? 'scan';
if ($action === 'save') {
$scanCfg['auto_scan_enabled'] = !empty($_POST['auto_scan_enabled']);
$r1 = bg_config_save_key('scan_config', json_encode($scanCfg, JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES)."\n");
$vtKey = trim($_POST['virustotal_key'] ?? '');
$cloudContent = 'malware_bazaar_api_key=' . $vtKey . "\n";
$r2 = bg_config_save_key('cloud', $cloudContent);
$ok = (($r1['code'] ?? 1) === 0) && (($r2['code'] ?? 1) === 0);
bg_flash($ok ? 'success' : 'warning', $ok ? bg_t('scan_settings_saved') : trim(($r1['output'] ?? '') . "\n" . ($r2['output'] ?? ''))); bg_redirect('scan.php');
} elseif ($action === 'scan') {
$path = trim($_POST['path'] ?? '');
if ($path === '' && !empty($_FILES['upload']['tmp_name'])) {
$tmpDir = bg_data_dir() . '/uploads'; if (!is_dir($tmpDir)) bg_safe_mkdir($tmpDir,0750);
$dest = $tmpDir . '/' . time() . '-' . bg_safe_basename($_FILES['upload']['name']);
if (@move_uploaded_file($_FILES['upload']['tmp_name'], $dest)) $path = $dest;
}
if ($path === '') $output = bg_t('no_path_or_file_specified');
else {
$res = bg_scan_path_privileged($path);
$output = ($res['output'] ?? '') . "\n\n" . bg_t('exit_code') . ": " . ($res['code'] ?? '?');
}
} elseif ($action === 'monitor-save') {
$paths = bg_normalize_lines($_POST['watch_paths'] ?? '');
if (!$paths) $paths = $defaultWatch;
bg_write_json('scan_inotify_paths.json', ['paths'=>$paths]);
$saveRes = bg_inotify_monitor_save($paths);
$msg = bg_language()==='en' ? 'Realtime inotify paths saved.' : 'Percorsi inotify salvati.';
if (($saveRes['code'] ?? 1) !== 0) $msg .= ' ' . trim((string)($saveRes['output'] ?? ''));
bg_flash(($saveRes['code'] ?? 1) === 0 ? 'success' : 'warning', $msg);
bg_redirect('scan.php#inotify');
} elseif ($action === 'monitor-start') {
$paths = bg_normalize_lines($_POST['watch_paths'] ?? '');
if (!$paths) $paths = $monitorPaths['paths'];
bg_write_json('scan_inotify_paths.json', ['paths'=>$paths]);
$res = bg_inotify_monitor_start($paths);
bg_flash(($res['code'] ?? 1) === 0 ? 'success' : 'warning', $res['output'] ?: bg_t('command_executed'));
bg_redirect('scan.php#inotify');
} elseif ($action === 'monitor-stop') {
$res = bg_inotify_monitor_stop();
bg_flash(($res['code'] ?? 1) === 0 ? 'success' : 'warning', $res['output'] ?: bg_t('command_executed'));
bg_redirect('scan.php#inotify');
}
}
$paths = bg_clamd_paths();
$clamonacc = bg_service_status(['clamav-clamonacc.service','clamonacc.service']);
$monStatus = bg_inotify_monitor_status();
$monEvents = bg_inotify_monitor_events(120);
include 'includes/header.php'; include 'includes/sidebar.php';
?>
<div class="page-title"><div><h1><?= bg_e(bg_t('scan_realtime')) ?></h1><p><?= bg_e(bg_t('scan_page_subtitle')) ?></p></div><?= bg_status_badge($clamonacc['active'], bg_t('realtime_active'), bg_t('realtime_stopped')) ?></div>
<div class="alert alert-secondary"><strong><?= bg_e(bg_t('sudoers')) ?>:</strong> <?= bg_e(bg_t('install_update_helpers_with')) ?> <code>sudo bash scripts/install-webui-helpers.sh &quot;$USER&quot;</code>. <?= bg_e(bg_t('scan_uses')) ?> <code>/usr/local/sbin/bastionguard-webui-admin scan-path-b64</code>; <?= bg_e(bg_t('realtime_monitor_runs_root')) ?> <code>bastionguard-webui-inotify.service</code> <?= bg_e(bg_t('and_uses')) ?> <code>inotifywait</code>, <code>clamdscan</code> and <code>BastionGuard-ransomware-realtime</code> <?= bg_e(bg_t('when_installed')) ?>.</div>
<div class="row g-4">
<div class="col-lg-6"><div class="card"><div class="card-body"><h5><?= bg_e(bg_t('manual_scan')) ?></h5><form method="post" enctype="multipart/form-data"><?php csrf_field(); ?><input type="hidden" name="action" value="scan"><label class="form-label"><?= bg_e(bg_t('local_path_to_scan')) ?></label><input class="form-control mb-2" name="path" placeholder="/home/user/Downloads or /srv/share"><div class="text-center text-muted my-2"><?= bg_e(bg_t('or')) ?></div><input class="form-control mb-3" type="file" name="upload"><button class="btn btn-primary"><i class="bi bi-search"></i> <?= bg_e(bg_t('start_scan')) ?></button></form><p class="form-hint mt-2"><?= bg_e(bg_t('paths_allowed_by_helper')) ?>: <code>/home</code>, <code>/home/*</code>, <code>/var/www</code>, <code>/srv</code>, <code>/mnt</code>, <code>/media</code>, <code>/run/media</code>, WebUI upload and <code>/tmp</code>.</p></div></div></div>
<div class="col-lg-6"><div class="card"><div class="card-body"><h5><?= bg_e(bg_t('automatic_scan')) ?></h5><form method="post"><?php csrf_field(); ?><input type="hidden" name="action" value="save"><div class="form-check form-switch mb-3"><input class="form-check-input" type="checkbox" name="auto_scan_enabled" value="1" <?= !empty($scanCfg['auto_scan_enabled'])?'checked':'' ?>><label class="form-check-label"><?= bg_e(bg_t('enable_automatic_scanning_events')) ?></label></div><label class="form-label"><?= bg_e(bg_t('malware_bazaar_api_key')) ?></label><input class="form-control" name="virustotal_key" value="<?= bg_e($cloudParsed['malware_bazaar_api_key'] ?? '') ?>" placeholder="<?= bg_e(bg_t('optional')) ?>"><button class="btn btn-outline-primary mt-3"><?= bg_e(bg_t('save_settings')) ?></button></form><p class="small-muted mt-2">Config: <code><?= bg_e(bg_config_catalog()['scan_config']['path']) ?></code> and <code><?= bg_e(bg_config_catalog()['cloud']['path']) ?></code>.</p></div></div></div>
<div class="col-lg-6"><div class="card"><div class="card-body"><h5><?= bg_e(bg_t('detected_onaccess_paths')) ?></h5><?php if($paths): ?><ul><?php foreach($paths as $p): ?><li><code><?= bg_e($p) ?></code></li><?php endforeach; ?></ul><?php else: ?><p class="text-muted"><?= bg_e(bg_t('no_onaccess_path')) ?></p><?php endif; ?></div></div></div>
<div class="col-lg-6" id="inotify"><div class="card h-100"><div class="card-body"><h5><?= bg_e(bg_t('inotify_monitor')) ?></h5><p class="small-muted"><?= bg_e(bg_t('status')) ?>: <code id="inotify-status"><?= bg_e(trim($monStatus['output'] ?? 'unknown')) ?></code></p><form method="post"><label class="form-label"><?= bg_e(bg_t('watch_paths_one_per_line')) ?></label><textarea class="form-control" name="watch_paths" rows="5"><?= bg_e(implode("\n", $monitorPaths['paths'])) ?></textarea><div class="d-flex gap-2 mt-3 flex-wrap"><?php csrf_field(); ?><button class="btn btn-outline-secondary" name="action" value="monitor-save"><i class="bi bi-save"></i> <?= bg_e(bg_t('save')) ?></button><button class="btn btn-success" name="action" value="monitor-start"><i class="bi bi-play"></i> <?= bg_e(bg_t('start_monitor')) ?></button><button class="btn btn-outline-danger" name="action" value="monitor-stop"><i class="bi bi-stop"></i> <?= bg_e(bg_t('stop_monitor')) ?></button></div></form><p class="form-hint mt-2"><?= bg_e(bg_t('requires')) ?> <code>inotify-tools</code>. <?= bg_e(bg_t('events_scanned_immediately')) ?> <code>BastionGuard-ransomware-realtime</code> <?= bg_e(bg_t('per_file_ransomware_scanner_when_available')) ?> <?= bg_e(bg_t('recommended_monitored_roots_include')) ?> <code>/tmp</code>, <?= bg_e(bg_t('user_web_roots_under')) ?> <code>/home</code>, <?= bg_e(bg_t('webserver_roots_such_as')) ?> <code>/var/www</code> or <code>/srv/http</code>. <?= bg_e(bg_t('malware_ransomware_create_alerts')) ?> <?= bg_e(bg_t('keep_monitor_active_after_logout')) ?> <code>sudo systemctl enable --now bastionguard-webui-inotify.service</code>.</p></div></div></div>
<div class="col-12"><div class="card"><div class="card-body"><div class="d-flex justify-content-between align-items-center"><h5><?= bg_e(bg_t('live_events')) ?></h5><span class="badge text-bg-secondary"><?= bg_e(bg_t('auto_refresh')) ?></span></div><pre class="log-box" id="inotify-events"><?= bg_e(trim($monEvents['output'] ?? '') ?: bg_t('no_realtime_events_yet')) ?></pre></div></div></div>
<?php if($output): ?><div class="col-12"><div class="card"><div class="card-body"><h5><?= bg_e(bg_t('scan_result')) ?></h5><?php bg_render_log($output); ?></div></div></div><?php endif; ?>
</div>
<script>
(function(){
var box=document.getElementById('inotify-events'), st=document.getElementById('inotify-status');
if(!box) return;
function apply(j){
if(!j) return;
if(st) st.textContent=j.status||'';
box.textContent=(j.events&&j.events.trim())?j.events:<?= json_encode(bg_t('no_realtime_events_yet')) ?>;
box.scrollTop=box.scrollHeight;
}
function poll(){fetch('scan_events.php',{credentials:'same-origin'}).then(function(r){return r.json();}).then(apply).catch(function(){});}
if(window.EventSource){
try{
var es=new EventSource('scan_events.php?stream=1');
es.addEventListener('scan', function(e){ try{ apply(JSON.parse(e.data)); }catch(_e){} });
es.onerror=function(){ es.close(); poll(); window.setInterval(poll,2000); };
return;
}catch(e){}
}
poll(); window.setInterval(poll,2000);
})();
</script>
<?php include 'includes/footer.php'; ?>