更新
This commit is contained in:
parent
977ce66110
commit
c4b1f8fd1b
562
admin.php
Normal file
562
admin.php
Normal file
@ -0,0 +1,562 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* SecHub - JSON文件排序管理页面
|
||||||
|
*/
|
||||||
|
|
||||||
|
// 访问密码配置
|
||||||
|
define('ADMIN_PASSWORD', 'sechub2024'); // 请修改为你的密码
|
||||||
|
|
||||||
|
session_start();
|
||||||
|
|
||||||
|
// 定义路径
|
||||||
|
$jsonDir = __DIR__ . '/assets/json/';
|
||||||
|
$dbDir = __DIR__ . '/assets/db/';
|
||||||
|
$dbPath = $dbDir . 'sechub.db';
|
||||||
|
|
||||||
|
// 确保数据库目录存在
|
||||||
|
if (!is_dir($dbDir)) {
|
||||||
|
mkdir($dbDir, 0755, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 引入数据库类
|
||||||
|
require_once __DIR__ . '/db.php';
|
||||||
|
|
||||||
|
// 处理登录
|
||||||
|
if (isset($_POST['login'])) {
|
||||||
|
if ($_POST['password'] === ADMIN_PASSWORD) {
|
||||||
|
$_SESSION['authenticated'] = true;
|
||||||
|
header('Location: admin.php');
|
||||||
|
exit;
|
||||||
|
} else {
|
||||||
|
$error = '密码错误!';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理登出
|
||||||
|
if (isset($_GET['logout'])) {
|
||||||
|
session_destroy();
|
||||||
|
header('Location: admin.php');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 检查是否已登录
|
||||||
|
if (!isset($_SESSION['authenticated']) || $_SESSION['authenticated'] !== true) {
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>SecHub - 管理登录</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="login-container">
|
||||||
|
<h1>🔐 SecHub 管理后台</h1>
|
||||||
|
<?php if (isset($error)): ?>
|
||||||
|
<div class="error"><?= htmlspecialchars($error) ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<form method="POST">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="password">访问密码</label>
|
||||||
|
<input type="password" id="password" name="password" required autofocus>
|
||||||
|
</div>
|
||||||
|
<button type="submit" name="login">登录</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
<?php
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理保存排序
|
||||||
|
if (isset($_POST['save_order']) && isset($_POST['orders'])) {
|
||||||
|
$success = false;
|
||||||
|
$message = '';
|
||||||
|
|
||||||
|
try {
|
||||||
|
// orders 数组已经按拖拽后的顺序排列
|
||||||
|
$newOrder = 1;
|
||||||
|
foreach ($_POST['orders'] as $filename) {
|
||||||
|
$filePath = $jsonDir . $filename;
|
||||||
|
|
||||||
|
if (file_exists($filePath)) {
|
||||||
|
// 读取JSON文件(保持原始格式)
|
||||||
|
$content = file_get_contents($filePath);
|
||||||
|
$data = json_decode($content, true);
|
||||||
|
|
||||||
|
if (json_last_error() === JSON_ERROR_NONE && is_array($data) && !empty($data)) {
|
||||||
|
// 只更新第一个数据项的 no 字段
|
||||||
|
$data[0]['no'] = $newOrder;
|
||||||
|
|
||||||
|
// 写回JSON文件(保持原有格式,不转义)
|
||||||
|
$newContent = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
|
||||||
|
file_put_contents($filePath, $newContent . "\n");
|
||||||
|
|
||||||
|
$newOrder++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$success = true;
|
||||||
|
$message = '排序保存成功!';
|
||||||
|
|
||||||
|
// 重新同步数据库
|
||||||
|
$database = new SecHubDatabase($dbPath, $jsonDir);
|
||||||
|
$database->syncJsonToDatabase();
|
||||||
|
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$message = '保存失败: ' . $e->getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理删除数据库
|
||||||
|
if (isset($_POST['delete_db'])) {
|
||||||
|
if (file_exists($dbPath)) {
|
||||||
|
unlink($dbPath);
|
||||||
|
$success = true;
|
||||||
|
$message = '数据库已删除!刷新页面后将重新创建。';
|
||||||
|
} else {
|
||||||
|
$message = '数据库文件不存在。';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取所有JSON文件信息
|
||||||
|
$jsonFiles = glob($jsonDir . '*.json');
|
||||||
|
$fileInfos = [];
|
||||||
|
|
||||||
|
foreach ($jsonFiles as $filePath) {
|
||||||
|
$filename = basename($filePath);
|
||||||
|
$content = file_get_contents($filePath);
|
||||||
|
$data = json_decode($content, true);
|
||||||
|
|
||||||
|
if (json_last_error() === JSON_ERROR_NONE && is_array($data) && !empty($data)) {
|
||||||
|
$firstItem = $data[0];
|
||||||
|
$fileInfos[] = [
|
||||||
|
'filename' => $filename,
|
||||||
|
'section' => $firstItem['section'] ?? pathinfo($filename, PATHINFO_FILENAME),
|
||||||
|
'no' => $firstItem['no'] ?? 0,
|
||||||
|
'item_count' => count($data) - 1 // 减去第一个配置项
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按当前 no 排序
|
||||||
|
usort($fileInfos, function($a, $b) {
|
||||||
|
return $a['no'] - $b['no'];
|
||||||
|
});
|
||||||
|
?>
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="zh-CN">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<link rel="shortcut icon" href="./assets/imgs/favicon.ico" type="image/x-icon">
|
||||||
|
<title>SecHub - 排序管理</title>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
:root {
|
||||||
|
--bg-primary: #f5f7fa;
|
||||||
|
--bg-secondary: #ffffff;
|
||||||
|
--text-primary: #2c3e50;
|
||||||
|
--text-secondary: #7f8c8d;
|
||||||
|
--border-color: #e0e6ed;
|
||||||
|
--accent-color: #3498db;
|
||||||
|
--success-color: #27ae60;
|
||||||
|
--warning-color: #f39c12;
|
||||||
|
--hover-bg: #f0f4f8;
|
||||||
|
--shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Microsoft YaHei', sans-serif;
|
||||||
|
background-color: var(--bg-primary);
|
||||||
|
color: var(--text-primary);
|
||||||
|
line-height: 1.6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 30px 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
padding: 30px;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
margin-bottom: 30px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 1.8em;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-info {
|
||||||
|
display: flex;
|
||||||
|
gap: 15px;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
padding: 10px 20px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 0.95em;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: all 0.2s ease;
|
||||||
|
text-decoration: none;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
background: var(--accent-color);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary:hover {
|
||||||
|
background: #2980b9;
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 4px 12px rgba(52, 152, 219, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-success {
|
||||||
|
background: var(--success-color);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-success:hover {
|
||||||
|
background: #229954;
|
||||||
|
transform: translateY(-2px);
|
||||||
|
box-shadow: 0 4px 12px rgba(39, 174, 96, 0.3);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-danger {
|
||||||
|
background: #e74c3c;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-danger:hover {
|
||||||
|
background: #c0392b;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert {
|
||||||
|
padding: 15px 20px;
|
||||||
|
border-radius: 8px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-success {
|
||||||
|
background: #d4edda;
|
||||||
|
color: #155724;
|
||||||
|
border: 1px solid #c3e6cb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert-warning {
|
||||||
|
background: #fff3cd;
|
||||||
|
color: #856404;
|
||||||
|
border: 1px solid #ffeaa7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table-container {
|
||||||
|
background: var(--bg-secondary);
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: var(--shadow);
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
thead {
|
||||||
|
background: var(--bg-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
padding: 15px 20px;
|
||||||
|
text-align: left;
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--text-primary);
|
||||||
|
border-bottom: 2px solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
td {
|
||||||
|
padding: 15px 20px;
|
||||||
|
border-bottom: 1px solid var(--border-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
tbody tr:hover {
|
||||||
|
background: var(--hover-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
tbody tr:last-child td {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.draggable-row {
|
||||||
|
cursor: move;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.draggable-row:hover {
|
||||||
|
background: var(--hover-bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.draggable-row.dragging {
|
||||||
|
opacity: 0.5;
|
||||||
|
background: #e3f2fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag-handle {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 1.2em;
|
||||||
|
cursor: move;
|
||||||
|
padding: 0 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-number {
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--accent-color);
|
||||||
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.filename {
|
||||||
|
font-family: 'Courier New', monospace;
|
||||||
|
font-size: 0.9em;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-name {
|
||||||
|
font-weight: 600;
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-count {
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-size: 0.9em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-small {
|
||||||
|
padding: 6px 12px;
|
||||||
|
font-size: 0.85em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip {
|
||||||
|
background: #e3f2fd;
|
||||||
|
border-left: 4px solid var(--accent-color);
|
||||||
|
padding: 15px 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
border-radius: 4px;
|
||||||
|
color: #1976d2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.container {
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
header {
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 15px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-info {
|
||||||
|
flex-direction: column;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
font-size: 0.85em;
|
||||||
|
}
|
||||||
|
|
||||||
|
th, td {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actions {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<header>
|
||||||
|
<div>
|
||||||
|
<h1>📊 SecHub 排序管理</h1>
|
||||||
|
<p style="color: var(--text-secondary); margin-top: 5px;">调整栏目显示顺序</p>
|
||||||
|
</div>
|
||||||
|
<div class="header-info">
|
||||||
|
<a href="?logout=1" class="btn btn-danger">退出登录</a>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<?php if (isset($success) && $success): ?>
|
||||||
|
<div class="alert alert-success">
|
||||||
|
✅ <?= htmlspecialchars($message) ?>
|
||||||
|
</div>
|
||||||
|
<?php elseif (isset($message)): ?>
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
⚠️ <?= htmlspecialchars($message) ?>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<div class="tip">
|
||||||
|
💡 <strong>提示:</strong>拖动行左侧的 ⋮⋮ 图标来调整顺序,序号会自动更新。修改后点击“保存排序”按钮即可生效。
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="table-container">
|
||||||
|
<form method="POST">
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th style="width: 50px;"></th>
|
||||||
|
<th style="width: 80px;">序列</th>
|
||||||
|
<th>文件名称</th>
|
||||||
|
<th>项目名称</th>
|
||||||
|
<th style="width: 120px;">内容条数</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="sortable-tbody">
|
||||||
|
<?php foreach ($fileInfos as $index => $info): ?>
|
||||||
|
<tr class="draggable-row" data-filename="<?= htmlspecialchars($info['filename']) ?>" draggable="true">
|
||||||
|
<td>
|
||||||
|
<span class="drag-handle">⋮⋮</span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="order-number"><?= $index + 1 ?></span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="filename"><?= htmlspecialchars($info['filename']) ?></span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="section-name"><?= htmlspecialchars($info['section']) ?></span>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="item-count"><?= $info['item_count'] ?> 个工具</span>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<!-- 隐藏表单字段,用于提交排序 -->
|
||||||
|
<div id="order-inputs" style="display: none;"></div>
|
||||||
|
|
||||||
|
<div style="padding: 20px; text-align: center; border-top: 2px solid var(--border-color); display: flex; gap: 15px; justify-content: center; flex-wrap: wrap;">
|
||||||
|
<button type="submit" name="save_order" class="btn btn-success" style="font-size: 1.1em; padding: 12px 40px;">
|
||||||
|
💾 保存排序
|
||||||
|
</button>
|
||||||
|
<button type="submit" name="delete_db" class="btn btn-danger" style="font-size: 1.1em; padding: 12px 40px;" onclick="return confirm('确定要删除数据库吗?这将导致下次访问时重新同步所有数据。')">
|
||||||
|
🗑️ 重置数据库
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
// 拖拽排序功能
|
||||||
|
let draggedRow = null;
|
||||||
|
const tbody = document.getElementById('sortable-tbody');
|
||||||
|
|
||||||
|
// 添加拖拽事件监听
|
||||||
|
tbody.addEventListener('dragstart', function(e) {
|
||||||
|
draggedRow = e.target.closest('.draggable-row');
|
||||||
|
if (draggedRow) {
|
||||||
|
draggedRow.classList.add('dragging');
|
||||||
|
e.dataTransfer.effectAllowed = 'move';
|
||||||
|
e.dataTransfer.setData('text/html', draggedRow.innerHTML);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
tbody.addEventListener('dragend', function(e) {
|
||||||
|
if (draggedRow) {
|
||||||
|
draggedRow.classList.remove('dragging');
|
||||||
|
draggedRow = null;
|
||||||
|
updateOrderNumbers();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
tbody.addEventListener('dragover', function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.dataTransfer.dropEffect = 'move';
|
||||||
|
|
||||||
|
const afterElement = getDragAfterElement(tbody, e.clientY);
|
||||||
|
if (afterElement == null) {
|
||||||
|
tbody.appendChild(draggedRow);
|
||||||
|
} else {
|
||||||
|
tbody.insertBefore(draggedRow, afterElement);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 获取拖拽位置后的元素
|
||||||
|
function getDragAfterElement(container, y) {
|
||||||
|
const draggableElements = [...container.querySelectorAll('.draggable-row:not(.dragging)')];
|
||||||
|
|
||||||
|
return draggableElements.reduce((closest, child) => {
|
||||||
|
const box = child.getBoundingClientRect();
|
||||||
|
const offset = y - box.top - box.height / 2;
|
||||||
|
|
||||||
|
if (offset < 0 && offset > closest.offset) {
|
||||||
|
return { offset: offset, element: child };
|
||||||
|
} else {
|
||||||
|
return closest;
|
||||||
|
}
|
||||||
|
}, { offset: Number.NEGATIVE_INFINITY }).element;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新序号显示
|
||||||
|
function updateOrderNumbers() {
|
||||||
|
const rows = tbody.querySelectorAll('.draggable-row');
|
||||||
|
rows.forEach((row, index) => {
|
||||||
|
const orderSpan = row.querySelector('.order-number');
|
||||||
|
if (orderSpan) {
|
||||||
|
orderSpan.textContent = index + 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 表单提交前生成隐藏输入字段
|
||||||
|
document.querySelector('form').addEventListener('submit', function(e) {
|
||||||
|
const orderInputs = document.getElementById('order-inputs');
|
||||||
|
orderInputs.innerHTML = ''; // 清空旧数据
|
||||||
|
|
||||||
|
const rows = tbody.querySelectorAll('.draggable-row');
|
||||||
|
rows.forEach((row, index) => {
|
||||||
|
const filename = row.getAttribute('data-filename');
|
||||||
|
const input = document.createElement('input');
|
||||||
|
input.type = 'hidden';
|
||||||
|
input.name = 'orders[]';
|
||||||
|
input.value = filename;
|
||||||
|
orderInputs.appendChild(input);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Binary file not shown.
@ -1,5 +1,6 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
"no": 2,
|
||||||
"section": "甲方/蓝队工具"
|
"section": "甲方/蓝队工具"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -21,5 +22,10 @@
|
|||||||
"name": "AppScan",
|
"name": "AppScan",
|
||||||
"url": "https://github.com/TongchengOpenSource/AppScan",
|
"url": "https://github.com/TongchengOpenSource/AppScan",
|
||||||
"description": "企业级自动化App隐私合规检测工具"
|
"description": "企业级自动化App隐私合规检测工具"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "蓝队工具箱",
|
||||||
|
"url": "http://github.com/abc123info/BlueTeamTools",
|
||||||
|
"description": "蓝队分析研判工具箱(小工具集)"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
"no": 1,
|
||||||
"section": "合集/导航"
|
"section": "合集/导航"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -17,4 +18,4 @@
|
|||||||
"url": "https://git.masonliu.com/MasonLiu/SecHub",
|
"url": "https://git.masonliu.com/MasonLiu/SecHub",
|
||||||
"description": "由本人开发的网安工具集网站"
|
"description": "由本人开发的网安工具集网站"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
46
assets/json/info.json
Normal file
46
assets/json/info.json
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"no": 5,
|
||||||
|
"section": "信息收集"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ENScan Go",
|
||||||
|
"url": "https://github.com/wgpsec/ENScan_GO",
|
||||||
|
"description": "一键收集控股公司ICP备案、APP、小程序、微信公众号等信息聚合导出"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "EHole(棱洞)",
|
||||||
|
"url": "https://github.com/EdgeSecurityTeam/EHole",
|
||||||
|
"description": "快速/高效的网站指纹识别组件,搭配子域名挖掘程序更好用"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Subfinder",
|
||||||
|
"url": "https://github.com/projectdiscovery/subfinder",
|
||||||
|
"description": "子域名资产收集发现程序,可以发现更多的隐藏资产"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Masscan",
|
||||||
|
"url": "https://github.com/robertdavidgraham/masscan",
|
||||||
|
"description": "快速的网络端口扫描工具"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "nmap",
|
||||||
|
"url": "https://nmap.org/",
|
||||||
|
"description": "经典网络端口扫描工具"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "RustScan",
|
||||||
|
"url": "https://github.com/bee-san/RustScan",
|
||||||
|
"description": "Rust编写的高速网络端口扫描工具"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "JSFinder",
|
||||||
|
"url": "https://github.com/Threezh1/JSFinder",
|
||||||
|
"description": "提取网站文件中的域名信息"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "LinkFinder",
|
||||||
|
"url": "https://github.com/GerbenJavado/LinkFinder",
|
||||||
|
"description": "提取网站文件中的路径信息"
|
||||||
|
}
|
||||||
|
]
|
||||||
@ -1,5 +1,6 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
"no": 8,
|
||||||
"section": "内网渗透工具"
|
"section": "内网渗透工具"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -46,5 +47,10 @@
|
|||||||
"name": "Pillager",
|
"name": "Pillager",
|
||||||
"url": "https://github.com/qwqdanchun/Pillager",
|
"url": "https://github.com/qwqdanchun/Pillager",
|
||||||
"description": "适用于后渗透期间的信息收集工具"
|
"description": "适用于后渗透期间的信息收集工具"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Mimikatz",
|
||||||
|
"url": "https://github.com/gentilkiwi/mimikatz",
|
||||||
|
"description": "获取目标机器权限后提取密码哈希值"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
"no": 11,
|
||||||
"section": "移动端渗透工具"
|
"section": "移动端渗透工具"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -12,4 +13,4 @@
|
|||||||
"url": "https://github.com/frida/frida",
|
"url": "https://github.com/frida/frida",
|
||||||
"description": "移动端内核Hook工具"
|
"description": "移动端内核Hook工具"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
16
assets/json/other.json
Normal file
16
assets/json/other.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"no": 13,
|
||||||
|
"section": "其他"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "红队安防守则",
|
||||||
|
"url": "https://github.com/qingluoyu/Pentest_baseline",
|
||||||
|
"description": "红队反溯源基线核查手册"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "f8x",
|
||||||
|
"url": "https://github.com/ffffffff0x/f8x",
|
||||||
|
"description": "红/蓝队环境自动化部署工具,支持多种场景"
|
||||||
|
}
|
||||||
|
]
|
||||||
@ -1,6 +1,7 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"section": "插件/非工具"
|
"no": 12,
|
||||||
|
"section": "插件/非独立工具"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "HaE",
|
"name": "HaE",
|
||||||
@ -11,5 +12,10 @@
|
|||||||
"name": "BurpCrypto",
|
"name": "BurpCrypto",
|
||||||
"url": "https://github.com/whwlsfb/BurpCrypto",
|
"url": "https://github.com/whwlsfb/BurpCrypto",
|
||||||
"description": "支持多种加密算法或直接执行JS代码的用于爆破前端加密的BurpSuite插件"
|
"description": "支持多种加密算法或直接执行JS代码的用于爆破前端加密的BurpSuite插件"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "FindSomething",
|
||||||
|
"url": "https://github.com/momosecurity/FindSomething",
|
||||||
|
"description": "浏览器用JS信息搜寻插件"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@ -1,12 +1,8 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
"no": 7,
|
||||||
"section": "POC/EXP"
|
"section": "POC/EXP"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "CVE-2026-31431",
|
|
||||||
"url": "https://copy.fail/",
|
|
||||||
"description": "基于复制功能的Linux系统提权漏洞"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "MS17-010检测工具",
|
"name": "MS17-010检测工具",
|
||||||
"url": "https://github.com/TeskeVirtualSystem/MS17010Test",
|
"url": "https://github.com/TeskeVirtualSystem/MS17010Test",
|
||||||
@ -22,4 +18,4 @@
|
|||||||
"url": "https://github.com/Dliv3/redis-rogue-server",
|
"url": "https://github.com/Dliv3/redis-rogue-server",
|
||||||
"description": "Redis未授权访问漏洞利用工具(Redis 4.x/5.x RCE)"
|
"description": "Redis未授权访问漏洞利用工具(Redis 4.x/5.x RCE)"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
"no": 10,
|
||||||
"section": "代理工具/集成平台"
|
"section": "代理工具/集成平台"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -27,4 +28,4 @@
|
|||||||
"url": "https://www.proxifier.com/",
|
"url": "https://www.proxifier.com/",
|
||||||
"description": "功能强大的网络代理工具,支持HTTP/HTTPS/SOCKS代理"
|
"description": "功能强大的网络代理工具,支持HTTP/HTTPS/SOCKS代理"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
21
assets/json/right.json
Normal file
21
assets/json/right.json
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"no": 9,
|
||||||
|
"section": "提权"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Windows",
|
||||||
|
"url": "https://github.com/SecWiki/windows-kernel-exploits",
|
||||||
|
"description": "Windows提权工具集"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Linux",
|
||||||
|
"url": "https://github.com/SecWiki/linux-kernel-exploits",
|
||||||
|
"description": "Linux提权工具集"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "CVE-2026-31431",
|
||||||
|
"url": "https://copy.fail/",
|
||||||
|
"description": "基于复制功能的Linux系统提权漏洞"
|
||||||
|
}
|
||||||
|
]
|
||||||
@ -1,5 +1,6 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
"no": 4,
|
||||||
"section": "多功能扫描器"
|
"section": "多功能扫描器"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -37,4 +38,4 @@
|
|||||||
"url": "https://gobies.org/",
|
"url": "https://gobies.org/",
|
||||||
"description": "自动化漏洞扫描工具,建议自行上网搜索红队破解版"
|
"description": "自动化漏洞扫描工具,建议自行上网搜索红队破解版"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@ -1,14 +1,15 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
"no": 3,
|
||||||
"section": "Shell管理工具"
|
"section": "Shell管理工具"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "AntSword蚁剑",
|
"name": "AntSword(蚁剑)",
|
||||||
"url": "https://github.com/AntSwordProject/antSword",
|
"url": "https://github.com/AntSwordProject/antSword",
|
||||||
"description": "AntSword蚁剑是一个功能强大的Shell管理工具,尤其是在PHP场景下"
|
"description": "AntSword蚁剑是一个功能强大的Shell管理工具,尤其是在PHP场景下"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Godzilla哥斯拉",
|
"name": "Godzilla(哥斯拉)",
|
||||||
"url": "https://github.com/BeichenDream/Godzilla",
|
"url": "https://github.com/BeichenDream/Godzilla",
|
||||||
"description": "多语言支持的强大Shell管理工具"
|
"description": "多语言支持的强大Shell管理工具"
|
||||||
},
|
},
|
||||||
@ -21,5 +22,10 @@
|
|||||||
"name": "ShellcodeLoader",
|
"name": "ShellcodeLoader",
|
||||||
"url": "https://github.com/knownsec/shellcodeloader",
|
"url": "https://github.com/knownsec/shellcodeloader",
|
||||||
"description": "shell免杀加密程序"
|
"description": "shell免杀加密程序"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Metasploit",
|
||||||
|
"url": "https://github.com/rapid7/metasploit-framework",
|
||||||
|
"description": "超级漏洞利用框架"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
"no": 6,
|
||||||
"section": "外网/打点工具"
|
"section": "外网/打点工具"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -17,29 +18,14 @@
|
|||||||
"url": "https://github.com/sqlmapproject/sqlmap",
|
"url": "https://github.com/sqlmapproject/sqlmap",
|
||||||
"description": "主流的强大SQL注入神器"
|
"description": "主流的强大SQL注入神器"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "ENScan Go",
|
|
||||||
"url": "https://github.com/wgpsec/ENScan_GO",
|
|
||||||
"description": "一键收集控股公司ICP备案、APP、小程序、微信公众号等信息聚合导出"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "dddd",
|
"name": "dddd",
|
||||||
"url": "https://github.com/SleepingBag945/dddd",
|
"url": "https://github.com/SleepingBag945/dddd",
|
||||||
"description": "用法简单的批量信息收集,供应链漏洞探测工具"
|
"description": "用法简单的批量信息收集,供应链漏洞探测工具"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"name": "EHole(棱洞)",
|
|
||||||
"url": "https://github.com/EdgeSecurityTeam/EHole",
|
|
||||||
"description": "快速/高效的网站指纹识别组件,搭配子域名挖掘程序更好用"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Subfinder",
|
|
||||||
"url": "https://github.com/projectdiscovery/subfinder",
|
|
||||||
"description": "子域名资产收集发现程序,可以发现更多的隐藏资产"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"name": "MDUT",
|
"name": "MDUT",
|
||||||
"url": "https://github.com/SafeGroceryStore/MDUT",
|
"url": "https://github.com/SafeGroceryStore/MDUT",
|
||||||
"description": "支持大量类型的数据库管理工具"
|
"description": "支持大量类型的数据库管理工具"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
"no": "0",
|
||||||
"section": "栏目名称"
|
"section": "栏目名称"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -8,13 +9,8 @@
|
|||||||
"description": "工具描述"
|
"description": "工具描述"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "工具名称",
|
"name": "",
|
||||||
"url": "工具链接",
|
"url": "",
|
||||||
"description": "工具描述"
|
"description": ""
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "工具名称",
|
|
||||||
"url": "工具链接",
|
|
||||||
"description": "工具描述"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
35
db.php
35
db.php
@ -66,6 +66,7 @@ class SecHubDatabase {
|
|||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
json_filename TEXT UNIQUE NOT NULL,
|
json_filename TEXT UNIQUE NOT NULL,
|
||||||
table_name TEXT NOT NULL,
|
table_name TEXT NOT NULL,
|
||||||
|
section_no INTEGER DEFAULT 0,
|
||||||
last_sync_time DATETIME NOT NULL,
|
last_sync_time DATETIME NOT NULL,
|
||||||
json_file_mtime INTEGER NOT NULL,
|
json_file_mtime INTEGER NOT NULL,
|
||||||
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||||
@ -115,6 +116,9 @@ class SecHubDatabase {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取排序号(从第一个数据项的 no 字段)
|
||||||
|
$sectionNo = $data[0]['no'] ?? 0;
|
||||||
|
|
||||||
// 创建或更新表
|
// 创建或更新表
|
||||||
$this->createTable($tableName, $data[0]);
|
$this->createTable($tableName, $data[0]);
|
||||||
|
|
||||||
@ -127,14 +131,14 @@ class SecHubDatabase {
|
|||||||
$this->insertItem($tableName, $item, $data[0]['section'] ?? $tableName);
|
$this->insertItem($tableName, $item, $data[0]['section'] ?? $tableName);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新同步日志
|
// 更新同步日志(包含排序号)
|
||||||
$this->updateSyncLog($filename, $tableName);
|
$this->updateSyncLog($filename, $tableName, $sectionNo);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更新同步日志
|
* 更新同步日志
|
||||||
*/
|
*/
|
||||||
private function updateSyncLog($filename, $tableName) {
|
private function updateSyncLog($filename, $tableName, $sectionNo = 0) {
|
||||||
$jsonFile = $this->jsonDir . $filename;
|
$jsonFile = $this->jsonDir . $filename;
|
||||||
$jsonModified = filemtime($jsonFile);
|
$jsonModified = filemtime($jsonFile);
|
||||||
$syncTime = date('Y-m-d H:i:s');
|
$syncTime = date('Y-m-d H:i:s');
|
||||||
@ -148,20 +152,22 @@ class SecHubDatabase {
|
|||||||
if ($exists) {
|
if ($exists) {
|
||||||
// 更新现有记录
|
// 更新现有记录
|
||||||
$sql = "UPDATE json_sync_log
|
$sql = "UPDATE json_sync_log
|
||||||
SET table_name = :table_name,
|
SET table_name = :table_name,
|
||||||
|
section_no = :section_no,
|
||||||
last_sync_time = :sync_time,
|
last_sync_time = :sync_time,
|
||||||
json_file_mtime = :mtime
|
json_file_mtime = :mtime
|
||||||
WHERE json_filename = :filename";
|
WHERE json_filename = :filename";
|
||||||
} else {
|
} else {
|
||||||
// 插入新记录
|
// 插入新记录
|
||||||
$sql = "INSERT INTO json_sync_log (json_filename, table_name, last_sync_time, json_file_mtime)
|
$sql = "INSERT INTO json_sync_log (json_filename, table_name, section_no, last_sync_time, json_file_mtime)
|
||||||
VALUES (:filename, :table_name, :sync_time, :mtime)";
|
VALUES (:filename, :table_name, :section_no, :sync_time, :mtime)";
|
||||||
}
|
}
|
||||||
|
|
||||||
$stmt = $this->db->prepare($sql);
|
$stmt = $this->db->prepare($sql);
|
||||||
$stmt->execute([
|
$stmt->execute([
|
||||||
':filename' => $filename,
|
':filename' => $filename,
|
||||||
':table_name' => $tableName,
|
':table_name' => $tableName,
|
||||||
|
':section_no' => $sectionNo,
|
||||||
':sync_time' => $syncTime,
|
':sync_time' => $syncTime,
|
||||||
':mtime' => $jsonModified
|
':mtime' => $jsonModified
|
||||||
]);
|
]);
|
||||||
@ -344,6 +350,15 @@ class SecHubDatabase {
|
|||||||
|
|
||||||
foreach ($tables as $table) {
|
foreach ($tables as $table) {
|
||||||
$tableName = $table['name'];
|
$tableName = $table['name'];
|
||||||
|
|
||||||
|
// 从同步日志中获取排序号
|
||||||
|
$sql = "SELECT section_no FROM json_sync_log WHERE table_name = :table_name LIMIT 1";
|
||||||
|
$stmt = $this->db->prepare($sql);
|
||||||
|
$stmt->execute([':table_name' => $tableName]);
|
||||||
|
$log = $stmt->fetch();
|
||||||
|
$sectionNo = $log ? $log['section_no'] : 0;
|
||||||
|
|
||||||
|
// 获取栏目名称
|
||||||
$sql = "SELECT DISTINCT section FROM {$tableName} LIMIT 1";
|
$sql = "SELECT DISTINCT section FROM {$tableName} LIMIT 1";
|
||||||
$stmt = $this->db->query($sql);
|
$stmt = $this->db->query($sql);
|
||||||
$row = $stmt->fetch();
|
$row = $stmt->fetch();
|
||||||
@ -351,11 +366,17 @@ class SecHubDatabase {
|
|||||||
if ($row) {
|
if ($row) {
|
||||||
$sections[$tableName] = [
|
$sections[$tableName] = [
|
||||||
'title' => $row['section'],
|
'title' => $row['section'],
|
||||||
'table' => $tableName
|
'table' => $tableName,
|
||||||
|
'no' => $sectionNo
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 按 no 字段排序
|
||||||
|
uasort($sections, function($a, $b) {
|
||||||
|
return ($a['no'] ?? 0) - ($b['no'] ?? 0);
|
||||||
|
});
|
||||||
|
|
||||||
return $sections;
|
return $sections;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user