ai-sdl1-0 / index.html
hackaigc's picture
Add 2 files
d5b2e85 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI SDL Digital Twin Security Dashboard</title>
<script src="https://cdn.tailwindcss.com"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.7; }
}
@keyframes float {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-10px); }
}
@keyframes scanning {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
@keyframes progress {
0% { width: 0%; }
100% { width: 100%; }
}
@keyframes highlight {
0%, 100% { box-shadow: 0 0 0 0 rgba(59, 130, 246, 0); }
50% { box-shadow: 0 0 0 10px rgba(59, 130, 246, 0.3); }
}
.scanning-animation {
background: linear-gradient(90deg, #3b82f6, #8b5cf6, #3b82f6);
background-size: 200% 200%;
animation: scanning 3s ease infinite;
}
.risk-pulse {
animation: pulse 2s infinite;
}
.avatar-float {
animation: float 6s ease-in-out infinite;
}
.progress-animation {
animation: progress 5s linear infinite;
}
.highlight-animation {
animation: highlight 2s ease infinite;
}
.fade-in {
animation: fadeIn 0.5s ease-in;
}
@keyframes fadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.terminal-font {
font-family: 'Courier New', monospace;
}
.phase-active {
border-left: 4px solid #3b82f6;
background: rgba(59, 130, 246, 0.1);
}
.chat-message-enter {
animation: chatMessageEnter 0.3s ease-out;
}
@keyframes chatMessageEnter {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.risk-tag {
transition: all 0.2s ease;
}
.risk-tag:hover {
transform: scale(1.05);
}
</style>
</head>
<body class="bg-gray-900 text-gray-100 min-h-screen">
<div id="dashboard" class="container mx-auto px-4 py-8">
<!-- Header -->
<header class="flex justify-between items-center mb-8">
<div class="flex items-center space-x-4">
<div class="w-16 h-16 bg-blue-600 rounded-full flex items-center justify-center avatar-float highlight-animation">
<i class="fas fa-robot text-3xl text-white"></i>
</div>
<div>
<h1 class="text-3xl font-bold bg-gradient-to-r from-blue-400 to-purple-500 bg-clip-text text-transparent">AI SDL Security Twin</h1>
<p class="text-gray-400">Continuous Security Analysis Dashboard</p>
</div>
</div>
<div class="flex items-center space-x-4">
<div class="relative">
<div class="w-3 h-3 bg-green-500 rounded-full absolute -top-1 -right-1 animate-ping"></div>
<span class="px-4 py-2 bg-gray-800 rounded-lg flex items-center">
<span class="w-2 h-2 bg-green-500 rounded-full mr-2"></span>
<span>Active Scanning</span>
</span>
</div>
<button id="simulateBtn" class="px-4 py-2 bg-blue-600 hover:bg-blue-700 rounded-lg transition">
<i class="fas fa-play mr-2"></i>Start Simulation
</button>
</div>
</header>
<!-- Main Game Dashboard -->
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<!-- Left Column - AI Avatar and Activity -->
<div class="lg:col-span-1 space-y-6">
<!-- AI Avatar Card -->
<div class="bg-gray-800 rounded-xl p-6 shadow-lg">
<div class="flex flex-col items-center">
<div class="relative mb-4">
<div class="w-32 h-32 bg-gradient-to-br from-blue-500 to-purple-600 rounded-full flex items-center justify-center avatar-float">
<i class="fas fa-robot text-6xl text-white"></i>
</div>
<div class="absolute -bottom-2 -right-2 bg-blue-600 rounded-full p-2">
<i class="fas fa-shield-alt text-white"></i>
</div>
</div>
<h3 class="text-xl font-semibold">SDL Security Twin</h3>
<p class="text-gray-400 text-sm mb-4">Real-time Security Analysis Engine</p>
<div class="w-full bg-gray-700 rounded-full h-2 mb-2">
<div id="overallProgress" class="bg-blue-500 h-2 rounded-full progress-animation" style="width: 0%"></div>
</div>
<p class="text-xs text-gray-400">System Security Coverage</p>
</div>
</div>
<!-- Activity Log -->
<div class="bg-gray-800 rounded-xl p-6 shadow-lg h-full">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-semibold">Security Operations</h3>
<span class="text-xs bg-blue-900 text-blue-300 px-2 py-1 rounded">Live Feed</span>
</div>
<div class="space-y-4 h-96 overflow-y-auto pr-2" id="activityLog">
<!-- Activity items will be added here by JavaScript -->
</div>
</div>
</div>
<!-- Middle Column - SDL Process Visualization -->
<div class="lg:col-span-1">
<div class="bg-gray-800 rounded-xl p-6 shadow-lg h-full">
<h2 class="text-xl font-bold mb-6 text-center bg-gradient-to-r from-blue-400 to-purple-500 bg-clip-text text-transparent">SDL Security Pipeline</h2>
<div class="relative h-full">
<!-- SDL Process Visualization -->
<div class="space-y-8">
<!-- Requirement Design -->
<div class="phase-card" id="requirementDesign">
<div class="phase-icon">
<div class="w-10 h-10 rounded-full bg-blue-900 flex items-center justify-center">
<i class="fas fa-clipboard-list text-white"></i>
</div>
</div>
<div class="phase-content">
<h3 class="font-semibold">Requirement Design</h3>
<p class="text-sm text-gray-400 mb-2">Analyzing security requirements and threat models</p>
<div class="flex items-center text-xs">
<span class="mr-2">Status:</span>
<span class="px-2 py-1 bg-gray-700 text-gray-300 rounded">Waiting</span>
</div>
<div class="mt-2" id="requirementStats"></div>
</div>
<div class="phase-progress">
<div class="w-full bg-gray-700 rounded-full h-1.5">
<div class="phase-progress-bar bg-blue-500 h-1.5 rounded-full" style="width: 0%"></div>
</div>
</div>
</div>
<!-- Code Changes -->
<div class="phase-card" id="codeChanges">
<div class="phase-icon">
<div class="w-10 h-10 rounded-full bg-blue-900 flex items-center justify-center">
<i class="fas fa-code text-white"></i>
</div>
</div>
<div class="phase-content">
<h3 class="font-semibold">Code Changes</h3>
<p class="text-sm text-gray-400 mb-2">Reviewing code for vulnerabilities and best practices</p>
<div class="flex items-center text-xs">
<span class="mr-2">Status:</span>
<span class="px-2 py-1 bg-gray-700 text-gray-300 rounded">Waiting</span>
</div>
<div class="mt-2" id="codeStats"></div>
</div>
<div class="phase-progress">
<div class="w-full bg-gray-700 rounded-full h-1.5">
<div class="phase-progress-bar bg-blue-500 h-1.5 rounded-full" style="width: 0%"></div>
</div>
</div>
</div>
<!-- Security Testing -->
<div class="phase-card" id="securityTesting">
<div class="phase-icon">
<div class="w-10 h-10 rounded-full bg-blue-900 flex items-center justify-center">
<i class="fas fa-shield-alt text-white"></i>
</div>
</div>
<div class="phase-content">
<h3 class="font-semibold">Security Testing</h3>
<p class="text-sm text-gray-400 mb-2">Executing automated security tests on interfaces</p>
<div class="flex items-center text-xs">
<span class="mr-2">Status:</span>
<span class="px-2 py-1 bg-gray-700 text-gray-300 rounded">Waiting</span>
</div>
<div class="mt-2" id="testingStats"></div>
</div>
<div class="phase-progress">
<div class="w-full bg-gray-700 rounded-full h-1.5">
<div class="phase-progress-bar bg-blue-500 h-1.5 rounded-full" style="width: 0%"></div>
</div>
</div>
</div>
<!-- Release -->
<div class="phase-card" id="release">
<div class="phase-icon">
<div class="w-10 h-10 rounded-full bg-blue-900 flex items-center justify-center">
<i class="fas fa-rocket text-white"></i>
</div>
</div>
<div class="phase-content">
<h3 class="font-semibold">Release</h3>
<p class="text-sm text-gray-400 mb-2">Verifying security compliance before deployment</p>
<div class="flex items-center text-xs">
<span class="mr-2">Status:</span>
<span class="px-2 py-1 bg-gray-700 text-gray-300 rounded">Waiting</span>
</div>
<div class="mt-2" id="releaseStats"></div>
</div>
<div class="phase-progress">
<div class="w-full bg-gray-700 rounded-full h-1.5">
<div class="phase-progress-bar bg-blue-500 h-1.5 rounded-full" style="width: 0%"></div>
</div>
</div>
</div>
<!-- Online Operation -->
<div class="phase-card" id="onlineOperation">
<div class="phase-icon">
<div class="w-10 h-10 rounded-full bg-blue-900 flex items-center justify-center">
<i class="fas fa-globe text-white"></i>
</div>
</div>
<div class="phase-content">
<h3 class="font-semibold">Online Operation</h3>
<p class="text-sm text-gray-400 mb-2">Monitoring for vulnerabilities and attacks</p>
<div class="flex items-center text-xs">
<span class="mr-2">Status:</span>
<span class="px-2 py-1 bg-gray-700 text-gray-300 rounded">Waiting</span>
</div>
<div class="mt-2" id="operationStats"></div>
</div>
<div class="phase-progress">
<div class="w-full bg-gray-700 rounded-full h-1.5">
<div class="phase-progress-bar bg-blue-500 h-1.5 rounded-full" style="width: 0%"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Right Column - Alerts and Reports -->
<div class="lg:col-span-1 space-y-6">
<!-- Aggregated Risk Alerts -->
<div class="bg-gray-800 rounded-xl p-6 shadow-lg">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-semibold">Aggregated Risk Alerts</h3>
<div id="alertCounter" class="text-xs bg-red-900 text-red-300 px-2 py-1 rounded flex items-center">
<span class="w-2 h-2 bg-red-500 rounded-full mr-1 animate-pulse"></span>
<span>0 New</span>
</div>
</div>
<div class="space-y-4 h-64 overflow-y-auto" id="riskAlerts">
<div class="text-center py-8 text-gray-500">
<i class="fas fa-check-circle text-3xl mb-2"></i>
<p>No active risk alerts</p>
</div>
</div>
</div>
<!-- Project Risk Overview -->
<div class="bg-gray-800 rounded-xl p-6 shadow-lg">
<div class="flex justify-between items-center mb-4">
<h3 class="text-lg font-semibold">Project Risk Overview</h3>
<span class="text-xs bg-blue-900 text-blue-300 px-2 py-1 rounded">Live</span>
</div>
<div class="space-y-4 h-64 overflow-y-auto" id="projectRisks">
<div class="text-center py-8 text-gray-500">
<i class="fas fa-lock text-3xl mb-2"></i>
<p>No projects with risks detected</p>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Project Detail View (hidden by default) -->
<div id="projectDetail" class="container mx-auto px-4 py-8 hidden">
<div class="flex justify-between items-center mb-6">
<button id="backToDashboard" class="flex items-center text-blue-400 hover:text-blue-300 transition">
<i class="fas fa-arrow-left mr-2"></i> Back to Dashboard
</button>
<div class="flex items-center space-x-4">
<span class="px-3 py-1 bg-gray-700 rounded-full text-sm">Project Detail</span>
<div id="projectStatus" class="px-3 py-1 bg-red-900 text-red-300 rounded-full text-sm flex items-center">
<span class="w-2 h-2 bg-red-500 rounded-full mr-2 animate-pulse"></span>
<span>Security Risk</span>
</div>
</div>
</div>
<!-- Project Header -->
<div class="bg-gray-800 rounded-xl p-6 mb-6">
<div class="flex justify-between items-start">
<div>
<h2 id="projectName" class="text-2xl font-bold mb-1">Project Name</h2>
<p id="projectTeam" class="text-gray-400 mb-4">Team Name</p>
<div class="flex flex-wrap gap-2 mb-4" id="projectTags">
<!-- Project tags will be added here -->
</div>
</div>
<div class="flex items-center space-x-4">
<div class="text-center">
<div class="text-3xl font-bold text-red-400" id="riskCount">0</div>
<div class="text-xs text-gray-400">Security Risks</div>
</div>
<div class="text-center">
<div class="text-3xl font-bold text-blue-400" id="phaseCount">0</div>
<div class="text-xs text-gray-400">Affected Phases</div>
</div>
</div>
</div>
<!-- Project Risk Summary -->
<div class="mt-4">
<h3 class="font-semibold mb-2">Security Risk Summary</h3>
<div class="flex flex-wrap gap-2" id="riskSummary">
<!-- Risk summary tags will be added here -->
</div>
</div>
</div>
<!-- SDL Phase Tabs -->
<div class="mb-6">
<div class="flex overflow-x-auto border-b border-gray-700">
<button class="phase-tab active" data-phase="requirements">Requirements</button>
<button class="phase-tab" data-phase="code">Code</button>
<button class="phase-tab" data-phase="testing">Testing</button>
<button class="phase-tab" data-phase="release">Release</button>
<button class="phase-tab" data-phase="operation">Operation</button>
</div>
</div>
<!-- Phase Content -->
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
<!-- Left Column - Phase Content -->
<div class="lg:col-span-2 space-y-6">
<!-- Requirements Phase -->
<div class="phase-content active" id="requirementsContent">
<div class="bg-gray-800 rounded-xl p-6">
<h3 class="text-lg font-semibold mb-4 flex items-center">
<i class="fas fa-clipboard-list text-blue-400 mr-2"></i>
Requirements Analysis
</h3>
<div class="mb-6">
<h4 class="font-medium mb-2">Project Requirements</h4>
<div class="bg-gray-700 p-4 rounded-lg mb-4">
<p id="requirementsText" class="text-gray-300">Loading requirements...</p>
</div>
</div>
<div>
<h4 class="font-medium mb-2">Security Analysis Results</h4>
<div id="requirementsRisks" class="space-y-3">
<!-- Risks will be added here -->
</div>
</div>
</div>
</div>
<!-- Code Phase -->
<div class="phase-content hidden" id="codeContent">
<div class="bg-gray-800 rounded-xl p-6">
<h3 class="text-lg font-semibold mb-4 flex items-center">
<i class="fas fa-code text-blue-400 mr-2"></i>
Code Analysis
</h3>
<div class="mb-6">
<h4 class="font-medium mb-2">Code Changes</h4>
<div class="bg-gray-700 p-4 rounded-lg mb-4">
<div class="terminal-font text-sm text-gray-300 overflow-x-auto" id="codeSnippet">
<pre>Loading code changes...</pre>
</div>
</div>
</div>
<div>
<h4 class="font-medium mb-2">Security Analysis Results</h4>
<div id="codeRisks" class="space-y-3">
<!-- Risks will be added here -->
</div>
</div>
</div>
</div>
<!-- Testing Phase -->
<div class="phase-content hidden" id="testingContent">
<div class="bg-gray-800 rounded-xl p-6">
<h3 class="text-lg font-semibold mb-4 flex items-center">
<i class="fas fa-shield-alt text-blue-400 mr-2"></i>
Security Testing
</h3>
<div class="mb-6">
<h4 class="font-medium mb-2">Tested Interfaces</h4>
<div class="bg-gray-700 p-4 rounded-lg mb-4">
<div class="terminal-font text-sm text-gray-300" id="testedInterfaces">
Loading tested interfaces...
</div>
</div>
</div>
<div>
<h4 class="font-medium mb-2">Security Analysis Results</h4>
<div id="testingRisks" class="space-y-3">
<!-- Risks will be added here -->
</div>
</div>
</div>
</div>
<!-- Release Phase -->
<div class="phase-content hidden" id="releaseContent">
<div class="bg-gray-800 rounded-xl p-6">
<h3 class="text-lg font-semibold mb-4 flex items-center">
<i class="fas fa-rocket text-blue-400 mr-2"></i>
Release Analysis
</h3>
<div class="mb-6">
<h4 class="font-medium mb-2">Release Artifacts</h4>
<div class="bg-gray-700 p-4 rounded-lg mb-4">
<div class="terminal-font text-sm text-gray-300" id="releaseArtifacts">
Loading release artifacts...
</div>
</div>
</div>
<div>
<h4 class="font-medium mb-2">Security Analysis Results</h4>
<div id="releaseRisks" class="space-y-3">
<!-- Risks will be added here -->
</div>
</div>
</div>
</div>
<!-- Operation Phase -->
<div class="phase-content hidden" id="operationContent">
<div class="bg-gray-800 rounded-xl p-6">
<h3 class="text-lg font-semibold mb-4 flex items-center">
<i class="fas fa-globe text-blue-400 mr-2"></i>
Operation Monitoring
</h3>
<div class="mb-6">
<h4 class="font-medium mb-2">Runtime Metrics</h4>
<div class="bg-gray-700 p-4 rounded-lg mb-4">
<div class="terminal-font text-sm text-gray-300" id="runtimeMetrics">
Loading runtime metrics...
</div>
</div>
</div>
<div>
<h4 class="font-medium mb-2">Security Analysis Results</h4>
<div id="operationRisks" class="space-y-3">
<!-- Risks will be added here -->
</div>
</div>
</div>
</div>
</div>
<!-- Right Column - Repair Progress and AI Chat -->
<div class="lg:col-span-1 space-y-6">
<!-- Repair Progress -->
<div class="bg-gray-800 rounded-xl p-6">
<h3 class="text-lg font-semibold mb-4 flex items-center">
<i class="fas fa-tasks text-blue-400 mr-2"></i>
Repair Progress
</h3>
<div class="space-y-4">
<div>
<div class="flex justify-between text-sm mb-1">
<span>Requirements</span>
<span id="reqRepairPercent">0%</span>
</div>
<div class="w-full bg-gray-700 rounded-full h-2">
<div id="reqRepairBar" class="bg-blue-500 h-2 rounded-full" style="width: 0%"></div>
</div>
</div>
<div>
<div class="flex justify-between text-sm mb-1">
<span>Code</span>
<span id="codeRepairPercent">0%</span>
</div>
<div class="w-full bg-gray-700 rounded-full h-2">
<div id="codeRepairBar" class="bg-blue-500 h-2 rounded-full" style="width: 0%"></div>
</div>
</div>
<div>
<div class="flex justify-between text-sm mb-1">
<span>Testing</span>
<span id="testRepairPercent">0%</span>
</div>
<div class="w-full bg-gray-700 rounded-full h-2">
<div id="testRepairBar" class="bg-blue-500 h-2 rounded-full" style="width: 0%"></div>
</div>
</div>
<div>
<div class="flex justify-between text-sm mb-1">
<span>Release</span>
<span id="releaseRepairPercent">0%</span>
</div>
<div class="w-full bg-gray-700 rounded-full h-2">
<div id="releaseRepairBar" class="bg-blue-500 h-2 rounded-full" style="width: 0%"></div>
</div>
</div>
<div>
<div class="flex justify-between text-sm mb-1">
<span>Operation</span>
<span id="opRepairPercent">0%</span>
</div>
<div class="w-full bg-gray-700 rounded-full h-2">
<div id="opRepairBar" class="bg-blue-500 h-2 rounded-full" style="width: 0%"></div>
</div>
</div>
</div>
</div>
<!-- AI Chat Assistant -->
<div class="bg-gray-800 rounded-xl p-6 h-full">
<h3 class="text-lg font-semibold mb-4 flex items-center">
<i class="fas fa-robot text-blue-400 mr-2"></i>
Security Assistant
</h3>
<div class="chat-container h-96 flex flex-col">
<div class="chat-messages flex-1 overflow-y-auto mb-4 space-y-3" id="chatMessages">
<div class="chat-message chat-message-enter bg-gray-700 p-3 rounded-lg">
<div class="flex items-start">
<div class="mr-2 mt-1">
<div class="w-6 h-6 rounded-full bg-blue-600 flex items-center justify-center">
<i class="fas fa-robot text-xs text-white"></i>
</div>
</div>
<div>
<p class="text-sm">Hello! I'm your AI SDL Security Assistant. How can I help you with this project's security issues?</p>
</div>
</div>
</div>
</div>
<div class="chat-input flex">
<input type="text" placeholder="Ask about security risks..." class="flex-1 bg-gray-700 text-white px-4 py-2 rounded-l-lg focus:outline-none focus:ring-2 focus:ring-blue-500">
<button class="bg-blue-600 hover:bg-blue-700 px-4 py-2 rounded-r-lg transition">
<i class="fas fa-paper-plane"></i>
</button>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
// Sample data for the dashboard
const projects = [
{
id: 1,
name: "支付宝国补项目",
team: "Payment Team",
tags: ["Payment", "High Priority", "Government"],
requirements: "1. 用户补贴申请功能\n2. 补贴金额计算逻辑\n3. 多级审批流程\n4. 数据导出功能",
code: "// 补贴计算逻辑\nfunction calculateSubsidy(user) {\n let amount = 0;\n // 敏感信息硬编码\n const subsidyRate = 0.3; \n \n // SQL拼接风险\n const sql = `UPDATE users SET subsidy = ${amount} WHERE id = ${user.id}`;\n \n // 越权检查缺失\n return amount * subsidyRate;\n}",
interfaces: [
"POST /api/subsidy/apply",
"GET /api/subsidy/status/{id}",
"POST /api/subsidy/approve",
"GET /api/subsidy/export"
],
release: "Version 1.2.3\n- 包含已知漏洞的旧版依赖\n- 生产环境使用测试密钥\n- 日志配置暴露敏感信息",
operation: "CPU: 45%\nMemory: 1.2GB/2GB\nRequests: 1200/min\nSecurity Events:\n- 多次越权访问尝试\n- SQL注入攻击检测\n- 异常数据导出请求"
},
{
id: 2,
name: "微信小程序升级",
team: "WeChat Team",
tags: ["Mobile", "User Facing", "Feature Update"],
requirements: "1. 新用户注册流程\n2. 第三方登录集成\n3. 用户数据同步\n4. 支付功能增强",
code: "// 第三方登录处理\nfunction handleOAuth(provider) {\n // CSRF令牌缺失\n const user = getOAuthUser(provider);\n \n // XSS风险\n document.getElementById('welcome').innerHTML = `Welcome, ${user.name}!`;\n \n // 不安全的反序列化\n localStorage.setItem('user', JSON.stringify(user));\n}",
interfaces: [
"POST /api/auth/oauth/{provider}",
"GET /api/user/profile",
"POST /api/payment/create",
"GET /api/data/sync"
],
release: "Version 2.1.0\n- 未经安全测试的紧急修复\n- 错误的CORS配置\n- 调试模式在生产环境启用",
operation: "CPU: 32%\nMemory: 890MB/2GB\nRequests: 980/min\nSecurity Events:\n- 多次OAuth滥用尝试\n- XSS攻击检测\n- 异常支付请求"
},
{
id: 3,
name: "云存储优化",
team: "Cloud Team",
tags: ["Infrastructure", "Performance", "Backend"],
requirements: "1. 文件上传性能优化\n2. 存储成本降低方案\n3. 跨区域复制功能\n4. 访问控制增强",
code: "// 文件上传处理\nasync function uploadFile(file) {\n // 不充分的文件类型检查\n if (!file.type) return false;\n \n // 权限检查缺失\n const path = `user_uploads/${user.id}/${file.name}`;\n \n // 路径遍历风险\n await s3.putObject({\n Bucket: 'my-bucket',\n Key: path,\n Body: file.data\n });\n}",
interfaces: [
"POST /api/storage/upload",
"GET /api/storage/download/{id}",
"POST /api/storage/copy",
"GET /api/storage/list"
],
release: "Version 1.5.2\n- 过期的SSL证书\n- 存储桶公开访问配置\n- 缺少必要的IAM策略",
operation: "CPU: 28%\nMemory: 1.5GB/4GB\nRequests: 750/min\nSecurity Events:\n- 多次未授权访问尝试\n- 恶意文件上传检测\n- 异常数据复制请求"
}
];
const riskTypes = {
"需求设计": [
{ name: "越权访问风险", severity: "high", description: "需求中缺少必要的权限控制描述,可能导致越权访问漏洞。" },
{ name: "数据隐私问题", severity: "critical", description: "需求中对敏感数据处理方式描述不足,可能导致数据泄露风险。" },
{ name: "日志记录不足", severity: "medium", description: "需求中未明确安全事件日志要求,影响安全审计能力。" },
{ name: "加密方案缺陷", severity: "high", description: "需求中指定的加密方案强度不足或实现方式不安全。" }
],
"代码变更": [
{ name: "SQL注入漏洞", severity: "critical", description: "代码中存在SQL拼接操作,可能导致SQL注入攻击。" },
{ name: "XSS漏洞", severity: "high", description: "代码中直接使用用户输入构建HTML,可能导致跨站脚本攻击。" },
{ name: "CSRF防护缺失", severity: "high", description: "代码中缺少CSRF防护措施,可能导致跨站请求伪造攻击。" },
{ name: "硬编码凭证", severity: "critical", description: "代码中包含硬编码的敏感凭证信息。" },
{ name: "缓冲区溢出", severity: "critical", description: "代码中存在不安全的缓冲区操作,可能导致内存破坏漏洞。" }
],
"安全测试": [
{ name: "JWT实现缺陷", severity: "high", description: "接口JWT实现存在安全缺陷,可能导致认证绕过。" },
{ name: "敏感信息泄露", severity: "critical", description: "接口响应中包含敏感信息,可能导致数据泄露。" },
{ name: "接口未授权访问", severity: "critical", description: "接口缺少必要的授权检查,可能导致未授权访问。" },
{ name: "速率限制缺失", severity: "medium", description: "接口缺少请求速率限制,可能导致暴力破解攻击。" }
],
"发布": [
{ name: "未修复漏洞发布", severity: "critical", description: "发布包中包含已知但未修复的安全漏洞。" },
{ name: "配置错误", severity: "high", description: "生产环境配置存在安全缺陷,如调试模式启用等。" },
{ name: "密钥泄露", severity: "critical", description: "发布包中包含敏感密钥或凭证信息。" },
{ name: "依赖漏洞", severity: "high", description: "项目依赖的第三方库包含已知安全漏洞。" }
],
"线上运行": [
{ name: "未修复漏洞", severity: "critical", description: "线上系统存在已知但未修复的安全漏洞。" },
{ name: "异常流量", severity: "high", description: "检测到异常访问模式,可能正在进行攻击尝试。" },
{ name: "入侵尝试", severity: "critical", description: "检测到明确的入侵尝试行为。" },
{ name: "数据泄露", severity: "critical", description: "检测到敏感数据异常访问或泄露迹象。" }
]
};
const phases = [
{ id: "requirementDesign", name: "需求设计", icon: "clipboard-list" },
{ id: "codeChanges", name: "代码变更", icon: "code" },
{ id: "securityTesting", name: "安全测试", icon: "shield-alt" },
{ id: "release", name: "发布", icon: "rocket" },
{ id: "onlineOperation", name: "线上运行", icon: "globe" }
];
let activities = [];
let detectedRisks = [];
let projectRiskMap = {};
let simulationInterval;
let isSimulating = false;
let currentProjectView = null;
// Function to update activity log
function updateActivityLog() {
const activityLog = document.getElementById('activityLog');
activityLog.innerHTML = '';
if (activities.length === 0) {
activityLog.innerHTML = `
<div class="text-center py-8 text-gray-500">
<i class="fas fa-info-circle text-3xl mb-2"></i>
<p>Waiting for security analysis to begin</p>
</div>
`;
return;
}
activities.slice(0, 10).forEach(activity => {
const activityItem = document.createElement('div');
activityItem.className = 'bg-gray-700 p-3 rounded-lg fade-in';
activityItem.innerHTML = `
<div class="flex justify-between items-start">
<div class="flex items-start">
<div class="mr-3 mt-1">
<div class="w-6 h-6 rounded-full ${activity.risk ? 'bg-red-600' : 'bg-blue-600'} flex items-center justify-center">
<i class="fas fa-${getActivityIcon(activity.action)} text-xs text-white"></i>
</div>
</div>
<div>
<p class="text-sm font-medium">${activity.action} <span class="${activity.risk ? 'text-red-400' : 'text-blue-400'}">${activity.project}</span></p>
<p class="text-xs text-gray-400">${activity.phase}${activity.time}</p>
${activity.risk ? `<p class="text-xs mt-1 text-red-300">Risk: ${activity.risk}</p>` : ''}
</div>
</div>
</div>
`;
activityLog.appendChild(activityItem);
});
}
// Function to update risk alerts
function updateRiskAlerts() {
const riskAlerts = document.getElementById('riskAlerts');
const alertCounter = document.getElementById('alertCounter');
if (detectedRisks.length === 0) {
riskAlerts.innerHTML = `
<div class="text-center py-8 text-gray-500">
<i class="fas fa-check-circle text-3xl mb-2"></i>
<p>No active risk alerts</p>
</div>
`;
alertCounter.innerHTML = `
<span class="w-2 h-2 bg-gray-500 rounded-full mr-1"></span>
<span>0 New</span>
`;
return;
}
riskAlerts.innerHTML = '';
const newAlerts = detectedRisks.filter(r => r.new).length;
alertCounter.innerHTML = `
<span class="w-2 h-2 bg-red-500 rounded-full mr-1 animate-pulse"></span>
<span>${newAlerts} New</span>
`;
detectedRisks.slice(0, 5).forEach(risk => {
const severityClass = risk.severity === 'critical' ? 'bg-red-900 text-red-300' :
risk.severity === 'high' ? 'bg-orange-900 text-orange-300' : 'bg-yellow-900 text-yellow-300';
const alertItem = document.createElement('div');
alertItem.className = `bg-gray-700 p-4 rounded-lg border-l-4 ${risk.new ? 'border-red-500' : 'border-gray-600'} fade-in`;
alertItem.innerHTML = `
<div class="flex justify-between items-start">
<div>
<h4 class="font-semibold">${risk.project}</h4>
<p class="text-sm text-gray-400">${risk.phase}环节</p>
</div>
<span class="text-xs px-2 py-1 ${severityClass} rounded">${risk.severity === 'critical' ? '严重' : risk.severity === 'high' ? '高危' : '中危'}</span>
</div>
<p class="mt-2 text-sm">${risk.risk}</p>
<div class="flex justify-between items-center mt-3">
<span class="text-xs text-gray-400">${risk.time}</span>
<button class="text-xs bg-blue-600 hover:bg-blue-700 px-3 py-1 rounded transition view-detail" data-project-id="${risk.projectId}">详情</button>
</div>
`;
riskAlerts.appendChild(alertItem);
});
// Add event listeners to detail buttons
document.querySelectorAll('.view-detail').forEach(button => {
button.addEventListener('click', function() {
const projectId = this.getAttribute('data-project-id');
showProjectDetail(projectId);
});
});
}
// Function to update project risk overview
function updateProjectRiskOverview() {
const projectRisks = document.getElementById('projectRisks');
if (Object.keys(projectRiskMap).length === 0) {
projectRisks.innerHTML = `
<div class="text-center py-8 text-gray-500">
<i class="fas fa-lock text-3xl mb-2"></i>
<p>No projects with risks detected</p>
</div>
`;
return;
}
projectRisks.innerHTML = '';
Object.entries(projectRiskMap).forEach(([projectId, risks]) => {
const project = projects.find(p => p.id == projectId);
const projectItem = document.createElement('div');
projectItem.className = 'bg-gray-700 p-4 rounded-lg fade-in';
const riskPhases = [...new Set(risks.map(r => r.phase))];
const riskCount = risks.length;
projectItem.innerHTML = `
<div class="flex justify-between items-start">
<div>
<h4 class="font-semibold">${project.name}</h4>
<p class="text-xs text-gray-400">${project.team}</p>
</div>
<span class="text-xs px-2 py-1 ${riskCount > 2 ? 'bg-red-900 text-red-300' : 'bg-yellow-900 text-yellow-300'} rounded">
${riskCount} 风险
</span>
</div>
<div class="mt-3">
<p class="text-xs text-gray-400 mb-1">影响环节:</p>
<div class="flex flex-wrap gap-1">
${riskPhases.map(phase => `
<span class="text-xs px-2 py-1 bg-gray-600 rounded">${phase}</span>
`).join('')}
</div>
</div>
<div class="mt-3 flex justify-between items-center">
<button class="text-xs bg-blue-600 hover:bg-blue-700 px-3 py-1 rounded transition view-detail" data-project-id="${projectId}">详情</button>
<span class="text-xs text-gray-400">${risks[0].time}</span>
</div>
`;
projectRisks.appendChild(projectItem);
});
// Add event listeners to detail buttons
document.querySelectorAll('.view-detail').forEach(button => {
button.addEventListener('click', function() {
const projectId = this.getAttribute('data-project-id');
showProjectDetail(projectId);
});
});
}
// Function to update phase status
function updatePhaseStatus(phaseId, status, progress) {
const phaseElement = document.getElementById(phaseId);
const statusElement = phaseElement.querySelector('.phase-content div:nth-child(3) span:last-child');
const progressBar = phaseElement.querySelector('.phase-progress-bar');
// Update status
if (status === 'scanning') {
phaseElement.classList.add('phase-active');
statusElement.className = 'px-2 py-1 bg-blue-900 text-blue-300 rounded';
statusElement.textContent = 'Scanning';
progressBar.style.width = `${progress}%`;
} else if (status === 'risk-detected') {
phaseElement.classList.add('phase-active');
statusElement.className = 'px-2 py-1 bg-red-900 text-red-300 rounded';
statusElement.textContent = 'Risk Detected';
progressBar.style.width = '100%';
} else if (status === 'completed') {
phaseElement.classList.remove('phase-active');
statusElement.className = 'px-2 py-1 bg-green-900 text-green-300 rounded';
statusElement.textContent = 'Completed';
progressBar.style.width = '100%';
} else {
phaseElement.classList.remove('phase-active');
statusElement.className = 'px-2 py-1 bg-gray-700 text-gray-300 rounded';
statusElement.textContent = 'Waiting';
progressBar.style.width = '0%';
}
}
// Function to simulate phase scanning
function simulatePhaseScanning(phase) {
return new Promise(resolve => {
let progress = 0;
updatePhaseStatus(phase.id, 'scanning', progress);
const project = projects[Math.floor(Math.random() * projects.length)];
const hasRisk = Math.random() > 0.6;
let detectedRisk = null;
const interval = setInterval(() => {
progress += 10;
updatePhaseStatus(phase.id, 'scanning', progress);
// Randomly detect risk during scanning
if (hasRisk && progress > 30 && progress < 80 && !detectedRisk) {
if (Math.random() > 0.7) {
const riskType = riskTypes[phase.name][Math.floor(Math.random() * riskTypes[phase.name].length)];
detectedRisk = {
project: project.name,
projectId: project.id,
phase: phase.name,
risk: riskType.name,
severity: riskType.severity,
description: riskType.description,
time: getRelativeTime(),
new: true
};
// Add to detected risks
detectedRisks.unshift(detectedRisk);
// Add to project risk map
if (!projectRiskMap[project.id]) {
projectRiskMap[project.id] = [];
}
projectRiskMap[project.id].push(detectedRisk);
// Add to activity log
activities.unshift({
action: "检测到风险",
phase: phase.name,
project: project.name,
risk: detectedRisk.risk,
time: getRelativeTime()
});
updatePhaseStatus(phase.id, 'risk-detected', 100);
updateActivityLog();
updateRiskAlerts();
updateProjectRiskOverview();
}
}
if (progress >= 100) {
clearInterval(interval);
// Add completion activity if no risk was found
if (!hasRisk || !detectedRisk) {
activities.unshift({
action: "完成扫描",
phase: phase.name,
project: project.name,
time: getRelativeTime()
});
updateActivityLog();
}
updatePhaseStatus(phase.id, 'completed', 100);
resolve();
}
}, 300);
});
}
// Function to simulate full SDL cycle
async function simulateSDLCycle() {
for (const phase of phases) {
await simulatePhaseScanning(phase);
await new Promise(resolve => setTimeout(resolve, 1000));
}
// Mark all risks as not new after full cycle
detectedRisks.forEach(r => r.new = false);
updateRiskAlerts();
}
// Helper function to get relative time
function getRelativeTime() {
const minutesAgo = Math.floor(Math.random() * 10);
return minutesAgo === 0 ? '刚刚' : `${minutesAgo}分钟前`;
}
// Helper function to get activity icon
function getActivityIcon(action) {
if (action.includes('分析') || action.includes('扫描')) return 'search';
if (action.includes('检测')) return 'exclamation-triangle';
if (action.includes('完成')) return 'check-circle';
if (action.includes('报告')) return 'file-alt';
if (action.includes('监控')) return 'eye';
if (action.includes('验证')) return 'check-double';
if (action.includes('计划')) return 'calendar-alt';
return 'info-circle';
}
// Function to show project detail view
function showProjectDetail(projectId) {
const project = projects.find(p => p.id == projectId);
if (!project) return;
currentProjectView = project;
// Hide dashboard and show detail view
document.getElementById('dashboard').classList.add('hidden');
document.getElementById('projectDetail').classList.remove('hidden');
// Update project header
document.getElementById('projectName').textContent = project.name;
document.getElementById('projectTeam').textContent = project.team;
// Update project tags
const projectTags = document.getElementById('projectTags');
projectTags.innerHTML = '';
project.tags.forEach(tag => {
const tagElement = document.createElement('span');
tagElement.className = 'text-xs px-2 py-1 bg-gray-700 rounded-full';
tagElement.textContent = tag;
projectTags.appendChild(tagElement);
});
// Get all risks for this project
const projectRisks = projectRiskMap[projectId] || [];
// Update risk counts
document.getElementById('riskCount').textContent = projectRisks.length;
const riskPhases = [...new Set(projectRisks.map(r => r.phase))];
document.getElementById('phaseCount').textContent = riskPhases.length;
// Update risk summary
const riskSummary = document.getElementById('riskSummary');
riskSummary.innerHTML = '';
const uniqueRisks = {};
projectRisks.forEach(risk => {
if (!uniqueRisks[risk.risk]) {
uniqueRisks[risk.risk] = risk;
}
});
Object.values(uniqueRisks).forEach(risk => {
const severityClass = risk.severity === 'critical' ? 'bg-red-900 text-red-300' :
risk.severity === 'high' ? 'bg-orange-900 text-orange-300' : 'bg-yellow-900 text-yellow-300';
const riskTag = document.createElement('span');
riskTag.className = `text-xs px-2 py-1 ${severityClass} rounded-full risk-tag`;
riskTag.textContent = risk.risk;
riskTag.title = risk.description;
riskSummary.appendChild(riskTag);
});
// Update phase content
updatePhaseContent('requirements', project);
updatePhaseContent('code', project);
updatePhaseContent('testing', project);
updatePhaseContent('release', project);
updatePhaseContent('operation', project);
// Set random repair progress
document.getElementById('reqRepairPercent').textContent = `${Math.floor(Math.random() * 30)}%`;
document.getElementById('reqRepairBar').style.width = `${Math.floor(Math.random() * 30)}%`;
document.getElementById('codeRepairPercent').textContent = `${Math.floor(Math.random() * 50)}%`;
document.getElementById('codeRepairBar').style.width = `${Math.floor(Math.random() * 50)}%`;
document.getElementById('testRepairPercent').textContent = `${Math.floor(Math.random() * 70)}%`;
document.getElementById('testRepairBar').style.width = `${Math.floor(Math.random() * 70)}%`;
document.getElementById('releaseRepairPercent').textContent = `${Math.floor(Math.random() * 40)}%`;
document.getElementById('releaseRepairBar').style.width = `${Math.floor(Math.random() * 40)}%`;
document.getElementById('opRepairPercent').textContent = `${Math.floor(Math.random() * 20)}%`;
document.getElementById('opRepairBar').style.width = `${Math.floor(Math.random() * 20)}%`;
}
// Function to update phase content in detail view
function updatePhaseContent(phase, project) {
const risks = (projectRiskMap[project.id] || []).filter(r => {
if (phase === 'requirements') return r.phase === '需求设计';
if (phase === 'code') return r.phase === '代码变更';
if (phase === 'testing') return r.phase === '安全测试';
if (phase === 'release') return r.phase === '发布';
if (phase === 'operation') return r.phase === '线上运行';
return false;
});
// Update content
if (phase === 'requirements') {
document.getElementById('requirementsText').textContent = project.requirements;
const risksContainer = document.getElementById('requirementsRisks');
risksContainer.innerHTML = risks.length > 0 ? '' : '<p class="text-gray-500 text-sm">No security risks detected in this phase</p>';
risks.forEach(risk => {
const severityClass = risk.severity === 'critical' ? 'border-red-500 bg-red-900/20' :
risk.severity === 'high' ? 'border-orange-500 bg-orange-900/20' : 'border-yellow-500 bg-yellow-900/20';
const riskElement = document.createElement('div');
riskElement.className = `border-l-4 p-3 ${severityClass}`;
riskElement.innerHTML = `
<div class="flex justify-between items-start">
<h5 class="font-medium">${risk.risk}</h5>
<span class="text-xs px-2 py-1 ${severityClass.replace('border-l-4', '')} rounded">
${risk.severity === 'critical' ? '严重' : risk.severity === 'high' ? '高危' : '中危'}
</span>
</div>
<p class="text-sm mt-1 text-gray-300">${risk.description}</p>
<div class="mt-2 flex justify-between items-center">
<span class="text-xs text-gray-400">${risk.time}</span>
<button class="text-xs bg-blue-600 hover:bg-blue-700 px-2 py-1 rounded transition">标记为修复</button>
</div>
`;
risksContainer.appendChild(riskElement);
});
}
else if (phase === 'code') {
document.getElementById('codeSnippet').innerHTML = `<pre>${project.code}</pre>`;
const risksContainer = document.getElementById('codeRisks');
risksContainer.innerHTML = risks.length > 0 ? '' : '<p class="text-gray-500 text-sm">No security risks detected in this phase</p>';
risks.forEach(risk => {
const severityClass = risk.severity === 'critical' ? 'border-red-500 bg-red-900/20' :
risk.severity === 'high' ? 'border-orange-500 bg-orange-900/20' : 'border-yellow-500 bg-yellow-900/20';
const riskElement = document.createElement('div');
riskElement.className = `border-l-4 p-3 ${severityClass}`;
riskElement.innerHTML = `
<div class="flex justify-between items-start">
<h5 class="font-medium">${risk.risk}</h5>
<span class="text-xs px-2 py-1 ${severityClass.replace('border-l-4', '')} rounded">
${risk.severity === 'critical' ? '严重' : risk.severity === 'high' ? '高危' : '中危'}
</span>
</div>
<p class="text-sm mt-1 text-gray-300">${risk.description}</p>
<div class="mt-2 flex justify-between items-center">
<span class="text-xs text-gray-400">${risk.time}</span>
<button class="text-xs bg-blue-600 hover:bg-blue-700 px-2 py-1 rounded transition">标记为修复</button>
</div>
`;
risksContainer.appendChild(riskElement);
});
}
else if (phase === 'testing') {
document.getElementById('testedInterfaces').innerHTML = project.interfaces.map(i => `<div class="mb-1">${i}</div>`).join('');
const risksContainer = document.getElementById('testingRisks');
risksContainer.innerHTML = risks.length > 0 ? '' : '<p class="text-gray-500 text-sm">No security risks detected in this phase</p>';
risks.forEach(risk => {
const severityClass = risk.severity === 'critical' ? 'border-red-500 bg-red-900/20' :
risk.severity === 'high' ? 'border-orange-500 bg-orange-900/20' : 'border-yellow-500 bg-yellow-900/20';
const riskElement = document.createElement('div');
riskElement.className = `border-l-4 p-3 ${severityClass}`;
riskElement.innerHTML = `
<div class="flex justify-between items-start">
<h5 class="font-medium">${risk.risk}</h5>
<span class="text-xs px-2 py-1 ${severityClass.replace('border-l-4', '')} rounded">
${risk.severity === 'critical' ? '严重' : risk.severity === 'high' ? '高危' : '中危'}
</span>
</div>
<p class="text-sm mt-1 text-gray-300">${risk.description}</p>
<div class="mt-2 flex justify-between items-center">
<span class="text-xs text-gray-400">${risk.time}</span>
<button class="text-xs bg-blue-600 hover:bg-blue-700 px-2 py-1 rounded transition">标记为修复</button>
</div>
`;
risksContainer.appendChild(riskElement);
});
}
else if (phase === 'release') {
document.getElementById('releaseArtifacts').textContent = project.release;
const risksContainer = document.getElementById('releaseRisks');
risksContainer.innerHTML = risks.length > 0 ? '' : '<p class="text-gray-500 text-sm">No security risks detected in this phase</p>';
risks.forEach(risk => {
const severityClass = risk.severity === 'critical' ? 'border-red-500 bg-red-900/20' :
risk.severity === 'high' ? 'border-orange-500 bg-orange-900/20' : 'border-yellow-500 bg-yellow-900/20';
const riskElement = document.createElement('div');
riskElement.className = `border-l-4 p-3 ${severityClass}`;
riskElement.innerHTML = `
<div class="flex justify-between items-start">
<h5 class="font-medium">${risk.risk}</h5>
<span class="text-xs px-2 py-1 ${severityClass.replace('border-l-4', '')} rounded">
${risk.severity === 'critical' ? '严重' : risk.severity === 'high' ? '高危' : '中危'}
</span>
</div>
<p class="text-sm mt-1 text-gray-300">${risk.description}</p>
<div class="mt-2 flex justify-between items-center">
<span class="text-xs text-gray-400">${risk.time}</span>
<button class="text-xs bg-blue-600 hover:bg-blue-700 px-2 py-1 rounded transition">标记为修复</button>
</div>
`;
risksContainer.appendChild(riskElement);
});
}
else if (phase === 'operation') {
document.getElementById('runtimeMetrics').textContent = project.operation;
const risksContainer = document.getElementById('operationRisks');
risksContainer.innerHTML = risks.length > 0 ? '' : '<p class="text-gray-500 text-sm">No security risks detected in this phase</p>';
risks.forEach(risk => {
const severityClass = risk.severity === 'critical' ? 'border-red-500 bg-red-900/20' :
risk.severity === 'high' ? 'border-orange-500 bg-orange-900/20' : 'border-yellow-500 bg-yellow-900/20';
const riskElement = document.createElement('div');
riskElement.className = `border-l-4 p-3 ${severityClass}`;
riskElement.innerHTML = `
<div class="flex justify-between items-start">
<h5 class="font-medium">${risk.risk}</h5>
<span class="text-xs px-2 py-1 ${severityClass.replace('border-l-4', '')} rounded">
${risk.severity === 'critical' ? '严重' : risk.severity === 'high' ? '高危' : '中危'}
</span>
</div>
<p class="text-sm mt-1 text-gray-300">${risk.description}</p>
<div class="mt-2 flex justify-between items-center">
<span class="text-xs text-gray-400">${risk.time}</span>
<button class="text-xs bg-blue-600 hover:bg-blue-700 px-2 py-1 rounded transition">标记为修复</button>
</div>
`;
risksContainer.appendChild(riskElement);
});
}
}
// Start/stop simulation
document.getElementById('simulateBtn').addEventListener('click', function() {
const btn = this;
if (isSimulating) {
clearInterval(simulationInterval);
btn.innerHTML = '<i class="fas fa-play mr-2"></i>Start Simulation';
isSimulating = false;
// Reset all phases
phases.forEach(phase => {
updatePhaseStatus(phase.id, 'waiting', 0);
});
} else {
btn.innerHTML = '<i class="fas fa-stop mr-2"></i>Stop Simulation';
isSimulating = true;
// Start continuous simulation
simulateSDLCycle();
simulationInterval = setInterval(simulateSDLCycle, 25000);
}
});
// Back to dashboard button
document.getElementById('backToDashboard').addEventListener('click', function() {
document.getElementById('dashboard').classList.remove('hidden');
document.getElementById('projectDetail').classList.add('hidden');
});
// Phase tab switching
document.querySelectorAll('.phase-tab').forEach(tab => {
tab.addEventListener('click', function() {
// Update active tab
document.querySelectorAll('.phase-tab').forEach(t => t.classList.remove('active'));
this.classList.add('active');
// Update active content
const phase = this.getAttribute('data-phase');
document.querySelectorAll('.phase-content').forEach(c => c.classList.add('hidden'));
document.getElementById(`${phase}Content`).classList.remove('hidden');
});
});
// Simple chat functionality
document.querySelector('.chat-input button').addEventListener('click', function() {
const input = document.querySelector('.chat-input input');
const message = input.value.trim();
if (message === '') return;
// Add user message
const userMessage = document.createElement('div');
userMessage.className = 'chat-message chat-message-enter bg-blue-900/30 p-3 rounded-lg mb-3';
userMessage.innerHTML = `
<div class="flex items-start">
<div class="mr-2 mt-1">
<div class="w-6 h-6 rounded-full bg-blue-600 flex items-center justify-center">
<i class="fas fa-user text-xs text-white"></i>
</div>
</div>
<div>
<p class="text-sm">${message}</p>
</div>
</div>
`;
document.getElementById('chatMessages').appendChild(userMessage);
// Clear input
input.value = '';
// Add AI response after a delay
setTimeout(() => {
const responses = [
`关于${currentProjectView.name}项目的${message}问题,检测到的主要风险包括...`,
`针对${message},建议采取以下修复措施...`,
`在${currentProjectView.name}项目中,${message}相关的安全分析结果显示...`,
`关于${message}的安全建议:1. 更新依赖库 2. 加强输入验证 3. 实施更严格的访问控制`,
`项目${currentProjectView.name}${message}问题的根本原因是...`
];
const aiMessage = document.createElement('div');
aiMessage.className = 'chat-message chat-message-enter bg-gray-700 p-3 rounded-lg';
aiMessage.innerHTML = `
<div class="flex items-start">
<div class="mr-2 mt-1">
<div class="w-6 h-6 rounded-full bg-blue-600 flex items-center justify-center">
<i class="fas fa-robot text-xs text-white"></i>
</div>
</div>
<div>
<p class="text-sm">${responses[Math.floor(Math.random() * responses.length)]}</p>
</div>
</div>
`;
document.getElementById('chatMessages').appendChild(aiMessage);
// Scroll to bottom
document.getElementById('chatMessages').scrollTop = document.getElementById('chatMessages').scrollHeight;
}, 1000);
});
// Initialize the dashboard
document.addEventListener('DOMContentLoaded', () => {
updateActivityLog();
updateRiskAlerts();
updateProjectRiskOverview();
// Initialize all phases as waiting
phases.forEach(phase => {
updatePhaseStatus(phase.id, 'waiting', 0);
});
});
</script>
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=hackaigc/ai-sdl1-0" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
</html>