Files
CyberStrikeAI/web/templates/index.html
2025-11-15 17:50:47 +08:00

317 lines
18 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CyberStrikeAI - 自主渗透测试平台</title>
<link rel="stylesheet" href="/static/css/style.css">
</head>
<body>
<div id="login-overlay" class="login-overlay" style="display: none;">
<div class="login-card">
<div class="login-header">
<h2>登录 CyberStrike</h2>
<p class="login-subtitle">请输入配置中的访问密码</p>
</div>
<form id="login-form" class="login-form">
<div class="form-group">
<label for="login-password">密码</label>
<input type="password" id="login-password" placeholder="输入登录密码" required autocomplete="current-password" />
</div>
<div id="login-error" class="login-error" role="alert" style="display: none;"></div>
<button type="submit" class="btn-primary login-submit">登录</button>
</form>
</div>
</div>
<div class="container">
<header>
<div class="header-content">
<div class="logo">
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 2L2 7L12 12L22 7L12 2Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2 17L12 22L22 17" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M2 12L12 17L22 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
<h1>CyberStrike</h1>
</div>
<div class="header-right">
<p class="header-subtitle">安全测试平台</p>
<div class="header-actions">
<button class="monitor-btn" onclick="openMonitorPanel()" title="MCP 监控面板">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3 12h4l3 8 4-16 3 8h4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
<span>监控</span>
</button>
<button class="settings-btn" onclick="openSettings()" title="设置">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</button>
</div>
</div>
</div>
</header>
<div class="main-layout">
<!-- 历史对话侧边栏 -->
<aside class="sidebar">
<div class="sidebar-header">
<button class="new-chat-btn" onclick="startNewConversation()">
<span>+</span> 新对话
</button>
</div>
<div class="sidebar-content">
<div class="sidebar-title">历史对话</div>
<div id="conversations-list" class="conversations-list"></div>
</div>
</aside>
<!-- 对话界面 -->
<div class="chat-container">
<div id="active-tasks-bar" class="active-tasks-bar"></div>
<div id="chat-messages" class="chat-messages"></div>
<div class="chat-input-container">
<textarea id="chat-input" placeholder="输入测试目标或命令... (Shift+Enter 换行Enter 发送)" rows="1"></textarea>
<button onclick="sendMessage()">发送</button>
</div>
</div>
</div>
</div>
<!-- 设置模态框 -->
<div id="settings-modal" class="modal">
<div class="modal-content settings-modal-content">
<div class="modal-header">
<h2>系统设置</h2>
<span class="modal-close" onclick="closeSettings()">&times;</span>
</div>
<div class="modal-body settings-body">
<!-- OpenAI配置 -->
<div class="settings-section">
<h3>OpenAI 配置</h3>
<div class="settings-form">
<div class="form-group">
<label for="openai-base-url">Base URL <span style="color: red;">*</span></label>
<input type="text" id="openai-base-url" placeholder="https://api.openai.com/v1" required />
</div>
<div class="form-group">
<label for="openai-api-key">API Key <span style="color: red;">*</span></label>
<input type="password" id="openai-api-key" placeholder="输入OpenAI API Key" required />
</div>
<div class="form-group">
<label for="openai-model">模型 <span style="color: red;">*</span></label>
<input type="text" id="openai-model" placeholder="gpt-4" required />
</div>
</div>
</div>
<!-- MCP工具配置 -->
<div class="settings-section">
<h3>MCP 工具配置</h3>
<div class="tools-controls">
<div class="tools-actions">
<button class="btn-secondary" onclick="selectAllTools()">全选</button>
<button class="btn-secondary" onclick="deselectAllTools()">全不选</button>
<div class="search-box">
<input type="text" id="tools-search" placeholder="搜索工具..." onkeypress="handleSearchKeyPress(event)" oninput="if(this.value.trim() === '') clearSearch()" />
<button class="btn-search" onclick="searchTools()" title="搜索">🔍</button>
</div>
<div class="tools-stats" id="tools-stats"></div>
</div>
<div id="tools-list" class="tools-list"></div>
</div>
</div>
<!-- 外部MCP配置 -->
<div class="settings-section">
<h3>外部 MCP 配置</h3>
<div class="external-mcp-controls">
<div class="external-mcp-actions">
<button class="btn-primary" onclick="showAddExternalMCPModal()">添加外部MCP</button>
<button class="btn-secondary" onclick="loadExternalMCPs()">刷新</button>
<div class="external-mcp-stats" id="external-mcp-stats"></div>
</div>
<div id="external-mcp-list" class="external-mcp-list"></div>
</div>
</div>
<!-- Agent配置 -->
<div class="settings-section">
<h3>Agent 配置</h3>
<div class="settings-form">
<div class="form-group">
<label for="agent-max-iterations">最大迭代次数</label>
<input type="number" id="agent-max-iterations" min="1" max="100" placeholder="30" />
</div>
</div>
</div>
<!-- 安全设置 -->
<div class="settings-section">
<h3>安全设置</h3>
<div class="settings-form">
<div class="form-group">
<label for="auth-current-password">当前密码</label>
<input type="password" id="auth-current-password" placeholder="输入当前登录密码" autocomplete="current-password" />
</div>
<div class="form-group">
<label for="auth-new-password">新密码</label>
<input type="password" id="auth-new-password" placeholder="设置新密码(至少 8 位)" autocomplete="new-password" />
</div>
<div class="form-group">
<label for="auth-confirm-password">确认新密码</label>
<input type="password" id="auth-confirm-password" placeholder="再次输入新密码" autocomplete="new-password" />
</div>
<div class="form-actions">
<button class="btn-secondary" type="button" onclick="resetPasswordForm()">清空</button>
<button class="btn-primary change-password-submit" type="button" onclick="changePassword()">修改密码</button>
</div>
<p class="password-hint">修改密码后,需要使用新密码重新登录。</p>
</div>
</div>
</div>
<div class="modal-footer">
<button class="btn-secondary" onclick="closeSettings()">取消</button>
<button class="btn-primary" onclick="applySettings()">应用配置</button>
</div>
</div>
</div>
<!-- 监控面板模态框 -->
<div id="monitor-modal" class="modal">
<div class="modal-content monitor-modal-content">
<div class="modal-header">
<h2>MCP 监控面板</h2>
<span class="modal-close" onclick="closeMonitorPanel()">&times;</span>
</div>
<div class="monitor-modal-body">
<div class="monitor-sections">
<section class="monitor-section monitor-overview">
<div class="section-header">
<h3>执行统计</h3>
<button class="btn-secondary" onclick="refreshMonitorPanel()">刷新</button>
</div>
<div id="monitor-stats" class="monitor-stats-grid">
<div class="monitor-empty">加载中...</div>
</div>
</section>
<section class="monitor-section monitor-executions">
<div class="section-header">
<h3>最新执行记录</h3>
<div class="section-actions">
<label>
状态筛选
<select id="monitor-status-filter" onchange="applyMonitorFilters()">
<option value="all">全部</option>
<option value="completed">已完成</option>
<option value="running">执行中</option>
<option value="failed">失败</option>
</select>
</label>
</div>
</div>
<div id="monitor-executions" class="monitor-table-container">
<div class="monitor-empty">加载中...</div>
</div>
</section>
</div>
</div>
</div>
</div>
<!-- MCP调用详情模态框 -->
<div id="mcp-detail-modal" class="modal">
<div class="modal-content">
<div class="modal-header">
<h2>工具调用详情</h2>
<span class="modal-close" onclick="closeMCPDetail()">&times;</span>
</div>
<div class="modal-body">
<div class="detail-section">
<h3>执行信息</h3>
<div class="detail-item">
<strong>工具:</strong> <span id="detail-tool-name"></span>
</div>
<div class="detail-item">
<strong>状态:</strong> <span id="detail-status"></span>
</div>
<div class="detail-item">
<strong>时间:</strong> <span id="detail-time"></span>
</div>
<div class="detail-item">
<strong>ID:</strong> <span id="detail-execution-id" style="font-family: monospace; font-size: 0.8125rem; color: var(--text-secondary);"></span>
</div>
</div>
<div class="detail-section">
<h3>请求参数</h3>
<pre id="detail-request" class="code-block"></pre>
</div>
<div class="detail-section">
<h3>响应结果</h3>
<pre id="detail-response" class="code-block"></pre>
</div>
<div class="detail-section" id="detail-error-section" style="display: none;">
<h3>错误信息</h3>
<pre id="detail-error" class="code-block error"></pre>
</div>
</div>
</div>
</div>
<!-- 外部MCP配置模态框 -->
<div id="external-mcp-modal" class="modal">
<div class="modal-content" style="max-width: 900px;">
<div class="modal-header">
<h2 id="external-mcp-modal-title">添加外部MCP</h2>
<span class="modal-close" onclick="closeExternalMCPModal()">&times;</span>
</div>
<div class="modal-body">
<div class="form-group">
<label for="external-mcp-json">配置JSON <span style="color: red;">*</span></label>
<textarea id="external-mcp-json" rows="15" placeholder='{\n "hexstrike-ai": {\n "command": "python3",\n "args": ["/path/to/script.py"],\n "description": "描述",\n "timeout": 300\n }\n}' style="font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace; font-size: 0.875rem; line-height: 1.5;"></textarea>
<div class="password-hint">
<strong>配置格式:</strong>JSON对象key为配置名称value为配置内容。状态通过"启动/停止"按钮控制无需在JSON中配置。<br>
<strong>配置示例:</strong><br>
<strong>stdio模式</strong><br>
<code style="display: block; margin: 8px 0; padding: 8px; background: var(--bg-secondary); border-radius: 4px; white-space: pre-wrap;">{
"hexstrike-ai": {
"command": "python3",
"args": ["/path/to/script.py", "--server", "http://example.com"],
"description": "描述",
"timeout": 300
}
}</code>
<strong>HTTP模式</strong><br>
<code style="display: block; margin: 8px 0; padding: 8px; background: var(--bg-secondary); border-radius: 4px; white-space: pre-wrap;">{
"cyberstrike-ai-http": {
"transport": "http",
"url": "http://127.0.0.1:8081/mcp"
}
}</code>
</div>
<div id="external-mcp-json-error" class="error-message" style="display: none; margin-top: 8px; padding: 8px; background: rgba(220, 53, 69, 0.1); border: 1px solid rgba(220, 53, 69, 0.3); border-radius: 4px; color: var(--error-color); font-size: 0.875rem;"></div>
</div>
<div class="form-group">
<button type="button" class="btn-secondary" onclick="formatExternalMCPJSON()" style="margin-top: 8px;">格式化JSON</button>
<button type="button" class="btn-secondary" onclick="loadExternalMCPExample()" style="margin-top: 8px; margin-left: 8px;">加载示例</button>
</div>
</div>
<div class="modal-footer">
<button class="btn-secondary" onclick="closeExternalMCPModal()">取消</button>
<button class="btn-primary" onclick="saveExternalMCP()">保存</button>
</div>
</div>
</div>
<!-- Marked.js for Markdown parsing -->
<script src="https://cdn.jsdelivr.net/npm/marked@11.1.1/marked.min.js"></script>
<!-- DOMPurify for HTML sanitization to prevent XSS -->
<script src="https://cdn.jsdelivr.net/npm/dompurify@3.0.8/dist/purify.min.js"></script>
<script src="/static/js/app.js"></script>
</body>
</html>