Initial commit

This commit is contained in:
Porawit Dongwang
2026-09-16 23:20:08 +07:00
commit 0041668dbb
32577 changed files with 3687927 additions and 0 deletions
@@ -0,0 +1,298 @@
<?php $pageTitle = __('System Settings'); ob_start(); ?>
<div class="max-w-7xl mx-auto mt-4">
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6 mb-6">
<!-- Integration Configuration -->
<div class="corp-card p-6 bg-white rounded-xl shadow-sm border border-slate-200">
<h3 class="text-lg font-bold text-slate-800 mb-6 border-b border-slate-200 pb-3 flex items-center">
<i class="fas fa-server text-slate-400 mr-2"></i> <?= __('Core Integration') ?>
</h3>
<div class="space-y-5">
<div class="bg-slate-50 p-4 rounded border border-slate-200">
<label class="block text-slate-600 text-xs font-bold mb-1 uppercase tracking-wide"><?= __('Wazuh Manager API URL') ?></label>
<input type="text" value="<?= htmlspecialchars($_ENV['WAZUH_API_URL'] ?? '') ?>" disabled class="border border-slate-300 rounded w-full py-2 px-3 text-slate-500 bg-white cursor-not-allowed font-mono text-sm shadow-sm">
</div>
<div class="bg-slate-50 p-4 rounded border border-slate-200">
<label class="block text-slate-600 text-xs font-bold mb-1 uppercase tracking-wide"><?= __('Wazuh Indexer URL') ?></label>
<input type="text" value="<?= htmlspecialchars($_ENV['WAZUH_INDEXER_URL'] ?? '') ?>" disabled class="border border-slate-300 rounded w-full py-2 px-3 text-slate-500 bg-white cursor-not-allowed font-mono text-sm shadow-sm">
</div>
<div class="bg-slate-50 p-4 rounded border border-slate-200">
<label class="block text-slate-600 text-xs font-bold mb-1 uppercase tracking-wide"><?= __('System Name (APP_NAME)') ?></label>
<input type="text" value="<?= htmlspecialchars($_ENV['APP_NAME'] ?? 'KSH SOAR') ?>" disabled class="border border-slate-300 rounded w-full py-2 px-3 text-slate-800 font-semibold bg-white cursor-not-allowed text-sm shadow-sm">
</div>
</div>
</div>
<!-- System Configuration -->
<div class="corp-card p-6 bg-white rounded-xl shadow-sm border border-slate-200">
<h3 class="text-lg font-bold text-slate-800 mb-6 border-b border-slate-200 pb-3 flex items-center">
<i class="fas fa-sliders-h text-slate-400 mr-2"></i> <?= __('Rule & Retention Policies') ?>
</h3>
<div class="space-y-5">
<div class="bg-slate-50 p-4 rounded border border-slate-200">
<label class="block text-slate-600 text-xs font-bold mb-1 uppercase tracking-wide"><?= __('Alert Retention Policy') ?></label>
<input type="text" value="<?= htmlspecialchars($_ENV['ALERT_RETENTION_DAYS'] ?? 90) ?> Days" disabled class="border border-slate-300 rounded w-full py-2 px-3 text-slate-800 font-semibold bg-white cursor-not-allowed text-sm shadow-sm">
</div>
<div class="bg-slate-50 p-4 rounded border border-slate-200">
<label class="block text-slate-600 text-xs font-bold mb-1 uppercase tracking-wide"><?= __('Alert Level Threshold') ?></label>
<input type="text" value="Level <?= htmlspecialchars($_ENV['MIN_ALERT_LEVEL'] ?? 7) ?>+" disabled class="border border-slate-300 rounded w-full py-2 px-3 text-slate-800 font-semibold bg-white cursor-not-allowed text-sm shadow-sm">
<p class="text-[10px] text-slate-400 mt-1">Configure <code class="bg-slate-200 px-1 rounded">MIN_ALERT_LEVEL</code> in .env</p>
</div>
<div class="bg-slate-50 p-4 rounded border border-slate-200">
<label class="block text-slate-600 text-xs font-bold mb-1 uppercase tracking-wide"><?= __('Excluded Rule IDs (Ignored Alerts)') ?></label>
<?php
$excluded = $_ENV['EXCLUDE_RULE_IDS'] ?? '';
$displayExcluded = empty($excluded) ? 'None (Log all rules)' : $excluded;
?>
<input type="text" value="<?= htmlspecialchars($displayExcluded) ?>" disabled class="border border-slate-300 rounded w-full py-2 px-3 text-slate-800 font-semibold bg-white cursor-not-allowed text-sm shadow-sm">
<p class="text-[10px] text-slate-400 mt-1">Configure <code class="bg-slate-200 px-1 rounded">EXCLUDE_RULE_IDS</code> in .env (Comma separated)</p>
</div>
<div class="bg-slate-50 p-4 rounded border border-slate-200">
<label class="block text-slate-600 text-xs font-bold mb-1 uppercase tracking-wide"><?= __('Resource Alert Threshold (RAM & Disk)') ?></label>
<div class="grid grid-cols-2 gap-4">
<div>
<p class="text-[10px] text-slate-500 font-bold mb-1"><?= __('RAM Alert Threshold (%)') ?></p>
<input type="text" value="<?= htmlspecialchars($_ENV['ALERT_RAM_PERCENT'] ?? '85') ?> %" disabled class="border border-slate-300 rounded w-full py-2 px-3 text-rose-600 font-bold bg-white cursor-not-allowed text-sm shadow-sm text-center">
<p class="text-[10px] text-slate-400 mt-1 text-center"><code class="bg-slate-200 px-1 rounded">ALERT_RAM_PERCENT</code></p>
</div>
<div>
<p class="text-[10px] text-slate-500 font-bold mb-1"><?= __('Disk Alert Threshold (%)') ?></p>
<input type="text" value="<?= htmlspecialchars($_ENV['ALERT_DISK_PERCENT'] ?? '85') ?> %" disabled class="border border-slate-300 rounded w-full py-2 px-3 text-rose-600 font-bold bg-white cursor-not-allowed text-sm shadow-sm text-center">
<p class="text-[10px] text-slate-400 mt-1 text-center"><code class="bg-slate-200 px-1 rounded">ALERT_DISK_PERCENT</code></p>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- <?= __('Notification Playbooks') ?> -->
<div class="corp-card p-6 bg-white rounded-xl shadow-sm border border-slate-200 mb-6">
<h4 class="text-lg font-bold text-slate-800 mb-4 border-b border-slate-200 pb-3 flex items-center">
<i class="fas fa-bell text-slate-400 mr-2"></i> <?= __('Notification Playbooks') ?>
</h4>
<div class="bg-blue-50/50 border border-blue-100 rounded p-3 mb-4 flex items-start text-sm text-blue-800">
<i class="fas fa-info-circle text-blue-500 mt-0.5 mr-2"></i>
<div>
<strong class="text-blue-900 font-semibold">กฎการแจ้งเตือนอัตโนมัติ:</strong>
ระบบจะส่งข้อความแจ้งเตือนเข้าแชทเฉพาะเมื่อตรวจพบภัยคุกคาม <b>Level 12 ขึ้นไป</b> (High / Critical) เพื่อป้องกันข้อความแจ้งเตือนเยอะเกินความจำเป็น
</div>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<!-- LINE Notify -->
<div class="bg-slate-50 p-4 rounded border border-slate-200">
<div class="flex justify-between items-center mb-2">
<label class="text-slate-600 text-xs font-bold uppercase tracking-wide"><i class="fab fa-line text-green-500 mr-1"></i> LINE Notify</label>
<?php if (!empty($_ENV['LINE_NOTIFY_TOKEN'])): ?>
<span class="bg-emerald-100 text-emerald-700 px-2 py-0.5 rounded text-[10px] font-bold uppercase">Configured</span>
<?php else: ?>
<span class="bg-rose-100 text-rose-700 px-2 py-0.5 rounded text-[10px] font-bold uppercase">Not Set</span>
<?php endif; ?>
</div>
<div class="flex items-center gap-2 mt-3">
<button onclick="testNotification(this, 'line')" class="corp-btn-secondary px-3 py-1.5 rounded text-xs w-full" <?= empty($_ENV['LINE_NOTIFY_TOKEN']) ? 'disabled opacity-50 cursor-not-allowed' : '' ?>>
<i class="fas fa-paper-plane mr-1"></i> Test LINE
</button>
</div>
</div>
<!-- Telegram Bot -->
<div class="bg-slate-50 p-4 rounded border border-slate-200">
<div class="flex justify-between items-center mb-2">
<label class="text-slate-600 text-xs font-bold uppercase tracking-wide"><i class="fab fa-telegram text-blue-500 mr-1"></i> Telegram Bot</label>
<?php if (!empty($_ENV['TELEGRAM_BOT_TOKEN']) && !empty($_ENV['TELEGRAM_CHAT_ID'])): ?>
<span class="bg-emerald-100 text-emerald-700 px-2 py-0.5 rounded text-[10px] font-bold uppercase">Configured</span>
<?php else: ?>
<span class="bg-rose-100 text-rose-700 px-2 py-0.5 rounded text-[10px] font-bold uppercase">Not Set</span>
<?php endif; ?>
</div>
<div class="flex items-center gap-2 mt-3">
<button onclick="testNotification(this, 'telegram')" class="corp-btn-secondary px-3 py-1.5 rounded text-xs w-full" <?= (empty($_ENV['TELEGRAM_BOT_TOKEN']) || empty($_ENV['TELEGRAM_CHAT_ID'])) ? 'disabled opacity-50 cursor-not-allowed' : '' ?>>
<i class="fas fa-paper-plane mr-1"></i> Test Telegram
</button>
</div>
</div>
</div>
</div>
<!-- <?= __('Data Management') ?> -->
<div class="corp-card p-6 bg-white rounded-xl shadow-sm border border-slate-200 mb-6">
<h4 class="text-lg font-bold text-slate-800 mb-4 border-b border-slate-200 pb-3 flex items-center">
<i class="fas fa-database text-slate-400 mr-2"></i> <?= __('Data Management') ?>
</h4>
<div class="bg-rose-50 p-5 rounded border border-rose-200 mb-6">
<div class="flex flex-col md:flex-row justify-between items-start md:items-center">
<div>
<h5 class="text-rose-800 font-bold text-sm"><?= __('Clear All Alerts') ?></h5>
<p class="text-rose-600 text-xs mt-1">This will permanently delete all alert records from the database. Cases and playbooks will not be deleted. This action cannot be undone.</p>
</div>
<button onclick="confirmClearAll()" class="mt-4 md:mt-0 bg-white text-rose-600 hover:bg-rose-600 hover:text-white border border-rose-300 hover:border-rose-600 px-5 py-2.5 rounded text-xs font-bold uppercase tracking-wide transition-colors whitespace-nowrap shadow-sm">
<i class="fas fa-trash-alt mr-1"></i> <?= __('Delete All Alerts') ?>
</button>
</div>
</div>
<?php if (!empty($deletionLogs)): ?>
<div>
<h5 class="text-slate-700 font-bold text-sm mb-3"><i class="fas fa-history text-slate-400 mr-1"></i> <?= __('Deletion History') ?></h5>
<div class="overflow-x-auto border border-slate-200 rounded-lg">
<table id="deletionHistoryTable" class="w-full text-left text-sm whitespace-nowrap">
<thead class="bg-slate-50 text-slate-500 text-xs uppercase">
<tr>
<th class="px-4 py-3 font-semibold"><?= __('Date Deleted') ?></th>
<th class="px-4 py-3 font-semibold"><?= __('Reason') ?></th>
<th class="px-4 py-3 font-semibold"><?= __('Records Deleted') ?></th>
<th class="px-4 py-3 font-semibold"><?= __('Data Date Range') ?></th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100 bg-white">
<?php foreach ($deletionLogs as $log): ?>
<tr class="hover:bg-slate-50">
<td class="px-4 py-3 text-slate-500 font-mono text-xs"><?= date('Y-m-d H:i', strtotime($log['created_at'])) ?></td>
<td class="px-4 py-3 text-slate-700 font-medium whitespace-normal break-words max-w-xs"><?= htmlspecialchars($log['reason']) ?></td>
<td class="px-4 py-3 text-rose-600 font-bold"><?= number_format($log['deleted_count']) ?></td>
<td class="px-4 py-3 text-slate-500 text-xs"><?= htmlspecialchars($log['date_range']) ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<?php endif; ?>
</div>
<!-- Notice -->
<div class="bg-slate-100 border-l-4 border-slate-400 p-4 text-sm text-slate-600 rounded mb-6">
<div class="flex">
<div class="flex-shrink-0">
<i class="fas fa-info-circle text-slate-500 mt-0.5"></i>
</div>
<div class="ml-3">
<p class="font-medium"><?= __('Configuration Management') ?></p>
<p class="mt-1">For security and compliance, system configurations are managed via environment variables (<code class="bg-slate-200 px-1 py-0.5 rounded text-xs">.env</code>) and cannot be modified through the web interface.</p>
</div>
</div>
</div>
</div>
<script>
function testNotification(btn, type) {
let originalHtml = btn.innerHTML;
btn.innerHTML = '<i class="fas fa-spinner fa-spin mr-1"></i> Sending...';
btn.disabled = true;
$.ajax({
url: '<?= $baseUrl ?>/api/test-notification',
method: 'POST',
data: { type: type },
success: function(res) {
if (res.status === 'success') {
Swal.fire('Success', res.message, 'success');
} else {
Swal.fire('Error', res.message, 'error');
}
},
error: function() {
Swal.fire('Error', 'Failed to connect to the server.', 'error');
},
complete: function() {
btn.innerHTML = originalHtml;
btn.disabled = false;
}
});
}
function confirmClearAll() {
Swal.fire({
title: 'Authentication Required',
html: `You are about to <b class="text-rose-600">permanently delete ALL alerts</b>.<br>Please enter a reason and authorization password to confirm.
<div class="mt-4">
<input id="swal-reason" autocomplete="off" class="swal2-input !w-full !m-0 !mt-2 text-sm" placeholder="ระบุเหตุผลในการลบข้อมูล (จำเป็น)">
<input id="swal-password" type="password" autocomplete="new-password" class="swal2-input !w-full !m-0 !mt-3 text-sm" placeholder="ใส่รหัสผ่านเพื่อยืนยัน (CLEAR_ALERTS_PASSWORD)">
</div>`,
icon: 'warning',
showCancelButton: true,
confirmButtonColor: '#e11d48',
cancelButtonColor: '#64748b',
confirmButtonText: '<i class="fas fa-trash-alt mr-1"></i> Verify & Delete',
focusConfirm: false,
preConfirm: () => {
const reason = document.getElementById('swal-reason').value;
const password = document.getElementById('swal-password').value;
if (!reason) {
Swal.showValidationMessage('กรุณาระบุเหตุผลในการลบข้อมูล');
return false;
}
if (!password) {
Swal.showValidationMessage('กรุณาใส่รหัสผ่านเพื่อยืนยัน');
return false;
}
return { reason: reason, password: password };
}
}).then((result) => {
if (result.isConfirmed) {
Swal.fire({
title: 'Deleting...',
text: 'Please wait while alerts are being removed',
allowOutsideClick: false,
didOpen: () => { Swal.showLoading(); }
});
$.ajax({
url: '<?= $baseUrl ?>/api/clear-all-alerts',
method: 'POST',
data: {
password: result.value.password,
reason: result.value.reason
},
success: function(res) {
if (res.status === 'success') {
Swal.fire('Deleted!', `Successfully removed ${res.deleted.toLocaleString()} alerts.`, 'success')
.then(() => { window.location.reload(); });
} else {
Swal.fire('Error', res.message, 'error');
}
},
error: function(xhr) {
let msg = 'Failed to communicate with the server.';
if (xhr.responseJSON && xhr.responseJSON.message) {
msg = xhr.responseJSON.message;
}
Swal.fire('Error', msg, 'error');
}
});
}
});
}
$(document).ready(function() {
if($('#deletionHistoryTable').length) {
$('#deletionHistoryTable').DataTable({
responsive: true,
order: [[0, 'desc']], // Sort by Date Deleted descending
pageLength: 5,
lengthMenu: [[5, 10, 25, 50, -1], [5, 10, 25, 50, "All"]],
language: {
search: "",
searchPlaceholder: "Search history..."
},
dom: '<"flex justify-between items-center mb-4 px-4 pt-4"lf>rt<"flex justify-between items-center mt-4 px-4 pb-4"ip>'
});
}
});
</script>
<?php
$content = ob_get_clean();
require __DIR__ . '/layout.php';
?>