secagentx 3.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- backend/__init__.py +1 -0
- backend/__main__.py +3 -0
- backend/_assets/config.yaml +195 -0
- backend/_assets/frontend/dist/assets/AgentsView-DFqRplI8.css +1 -0
- backend/_assets/frontend/dist/assets/AgentsView-DJTpfQ87.js +1 -0
- backend/_assets/frontend/dist/assets/AttackChainView-BVfI-SC6.js +1 -0
- backend/_assets/frontend/dist/assets/ChatView-Bg4nIlQ0.css +1 -0
- backend/_assets/frontend/dist/assets/ChatView-CRndtmEC.js +38 -0
- backend/_assets/frontend/dist/assets/DashboardView-BXs4AWv8.js +1 -0
- backend/_assets/frontend/dist/assets/DashboardView-WnHWiqBW.css +1 -0
- backend/_assets/frontend/dist/assets/EventDetailView-DQk6Qp7-.js +1 -0
- backend/_assets/frontend/dist/assets/EventDetailView-Dj-a-zWr.css +1 -0
- backend/_assets/frontend/dist/assets/EventsView-8xh8uKO0.js +1 -0
- backend/_assets/frontend/dist/assets/EventsView-BHfFn66K.css +1 -0
- backend/_assets/frontend/dist/assets/KnowledgeView-C2N3v9bF.css +1 -0
- backend/_assets/frontend/dist/assets/KnowledgeView-D54ODoC9.js +11 -0
- backend/_assets/frontend/dist/assets/LoginView-CjvFmo7C.js +1 -0
- backend/_assets/frontend/dist/assets/LoginView-D14FzcsP.css +1 -0
- backend/_assets/frontend/dist/assets/SettingsView-JOJuoABi.js +1 -0
- backend/_assets/frontend/dist/assets/UsersView-DhMXZhir.js +1 -0
- backend/_assets/frontend/dist/assets/_plugin-vue_export-helper-BDNMzG2s.js +1 -0
- backend/_assets/frontend/dist/assets/index-D9Su3fYY.css +1 -0
- backend/_assets/frontend/dist/assets/index-DBEjbyJR.js +4 -0
- backend/_assets/frontend/dist/assets/rolldown-runtime-DK3Fl9T5.js +1 -0
- backend/_assets/frontend/dist/assets/vendor-charts-Dh1nChzO.js +39 -0
- backend/_assets/frontend/dist/assets/vendor-icons-BTNgi7vU.js +1 -0
- backend/_assets/frontend/dist/assets/vendor-ui-Cdd65KTN.js +7367 -0
- backend/_assets/frontend/dist/assets/vendor-vue-CXKcZAmz.js +1 -0
- backend/_assets/frontend/dist/index.html +51 -0
- backend/_assets/frontend/index.html +46 -0
- backend/_assets/frontend/package-lock.json +2983 -0
- backend/_assets/frontend/package.json +37 -0
- backend/_assets/frontend/src/App.vue +231 -0
- backend/_assets/frontend/src/main.js +12 -0
- backend/_assets/frontend/src/router/index.js +117 -0
- backend/_assets/frontend/src/stores/chat.js +671 -0
- backend/_assets/frontend/src/styles/tokens.css +282 -0
- backend/_assets/frontend/src/utils/http.js +191 -0
- backend/_assets/frontend/src/views/AgentsView.vue +227 -0
- backend/_assets/frontend/src/views/AttackChainView.vue +210 -0
- backend/_assets/frontend/src/views/ChatView.vue +1107 -0
- backend/_assets/frontend/src/views/DashboardView.vue +514 -0
- backend/_assets/frontend/src/views/EventDetailView.vue +387 -0
- backend/_assets/frontend/src/views/EventsView.vue +253 -0
- backend/_assets/frontend/src/views/KnowledgeView.vue +883 -0
- backend/_assets/frontend/src/views/LoginView.vue +314 -0
- backend/_assets/frontend/src/views/SettingsView.vue +226 -0
- backend/_assets/frontend/src/views/UsersView.vue +235 -0
- backend/_assets/frontend/vite.config.js +55 -0
- backend/_assets/knowledge_data/compliance/regulations.json +383 -0
- backend/_assets/knowledge_data/cve/vulnerabilities.json +70720 -0
- backend/_assets/knowledge_data/mitre_attack/techniques.json +14097 -0
- backend/_assets/knowledge_data/remediation/remediation.json +574 -0
- backend/_assets/knowledge_data/threat_intel/actors.json +1602 -0
- backend/_assets/knowledge_data/threat_intel/malware.json +971 -0
- backend/agents/__init__.py +1 -0
- backend/agents/alert_filter/__init__.py +1 -0
- backend/agents/alert_filter/alert_filter_agent.py +88 -0
- backend/agents/analyst.py +331 -0
- backend/agents/base.py +553 -0
- backend/agents/classifier_agent.py +134 -0
- backend/agents/cot_engine.py +578 -0
- backend/agents/intel.py +46 -0
- backend/agents/knowledge/__init__.py +2 -0
- backend/agents/knowledge/agentic_rag.py +928 -0
- backend/agents/knowledge/knowledge_agent.py +47 -0
- backend/agents/registry.py +148 -0
- backend/agents/responder.py +51 -0
- backend/agents/summary_agent.py +219 -0
- backend/auto_ingestor.py +948 -0
- backend/auto_patrol.py +452 -0
- backend/cli_app.py +523 -0
- backend/config/__init__.py +20 -0
- backend/config/provider_profiles.py +416 -0
- backend/config/runtime_settings.py +84 -0
- backend/decision_fusion/__init__.py +32 -0
- backend/decision_fusion/base.py +127 -0
- backend/decision_fusion/dempster_shafer.py +419 -0
- backend/decision_fusion/weighted_average.py +141 -0
- backend/email_ingestor.py +588 -0
- backend/errors.py +243 -0
- backend/escalation.py +453 -0
- backend/evaluation/__init__.py +7 -0
- backend/evaluation/evaluator.py +197 -0
- backend/evaluation/metrics.py +210 -0
- backend/federation/__init__.py +22 -0
- backend/federation/core.py +743 -0
- backend/interface/__init__.py +1 -0
- backend/interface/api_server.py +1830 -0
- backend/interface/cli.py +671 -0
- backend/knowledge/__init__.py +11 -0
- backend/knowledge/compliance.py +101 -0
- backend/knowledge/cve_db.py +100 -0
- backend/knowledge/mitre_attack.py +457 -0
- backend/knowledge/remediation.py +84 -0
- backend/knowledge/threat_intel_kb.py +246 -0
- backend/llm/__init__.py +1 -0
- backend/llm/anthropic_compatible.py +191 -0
- backend/llm/base.py +81 -0
- backend/llm/deepseek.py +221 -0
- backend/llm/fallback.py +268 -0
- backend/llm/mock.py +204 -0
- backend/llm/openai_compatible.py +51 -0
- backend/llm/provider.py +217 -0
- backend/llm/qwen.py +218 -0
- backend/main.py +421 -0
- backend/memory/__init__.py +1 -0
- backend/memory/episodic_memory.py +132 -0
- backend/memory/manager.py +204 -0
- backend/memory/semantic_memory.py +156 -0
- backend/memory/session_memory.py +102 -0
- backend/ml_model/__init__.py +23 -0
- backend/ml_model/pipeline.py +191 -0
- backend/ml_model/trainer.py +627 -0
- backend/models/__init__.py +1 -0
- backend/models/event.py +62 -0
- backend/models/message.py +58 -0
- backend/models/output.py +1216 -0
- backend/monitoring/metrics.py +184 -0
- backend/orchestrator/__init__.py +17 -0
- backend/orchestrator/agent_router.py +145 -0
- backend/orchestrator/core.py +159 -0
- backend/orchestrator/dynamic_weights.py +287 -0
- backend/orchestrator/react_loop.py +1895 -0
- backend/orchestrator/risk_model.py +494 -0
- backend/orchestrator/risk_scorer.py +356 -0
- backend/reasoner/__init__.py +19 -0
- backend/reasoner/reasoner.py +316 -0
- backend/runtime_assets.py +45 -0
- backend/security/__init__.py +24 -0
- backend/security/adversarial/__init__.py +13 -0
- backend/security/adversarial/guard.py +121 -0
- backend/security/adversarial/redteam.py +121 -0
- backend/security/adversarial/scanner.py +208 -0
- backend/security/audit.py +118 -0
- backend/security/auth.py +283 -0
- backend/security/circuit_breaker.py +212 -0
- backend/security/dispatch.py +18 -0
- backend/security/ratelimit.py +237 -0
- backend/security/rbac.py +431 -0
- backend/security/refresh_sessions.py +193 -0
- backend/security/sanitizer.py +32 -0
- backend/storage/__init__.py +1 -0
- backend/storage/chroma_store.py +79 -0
- backend/storage/database.py +296 -0
- backend/storage/migrations/env.py +65 -0
- backend/storage/migrations/versions/0001_initial_schema.py +101 -0
- backend/storage/migrations/versions/0002_add_agent_logs_experiences.py +53 -0
- backend/storage/migrations/versions/0003_add_conversation_owner.py +30 -0
- backend/storage/models.py +194 -0
- backend/storage/repositories/__init__.py +1 -0
- backend/storage/repositories/asset_repo.py +86 -0
- backend/storage/repositories/conversation_repo.py +216 -0
- backend/storage/repositories/event_repo.py +76 -0
- backend/storage/repositories/trajectory_repo.py +324 -0
- backend/storage/retention.py +117 -0
- backend/tools/__init__.py +16 -0
- backend/tools/alert_filter.py +208 -0
- backend/tools/aliyun_firewall.py +237 -0
- backend/tools/aws_firewall.py +369 -0
- backend/tools/base.py +445 -0
- backend/tools/calling.py +207 -0
- backend/tools/cve_search.py +77 -0
- backend/tools/execution_engine.py +202 -0
- backend/tools/firewall.py +387 -0
- backend/tools/geoip.py +168 -0
- backend/tools/log_analyzer.py +185 -0
- backend/tools/ml_detector.py +226 -0
- backend/tools/registry.py +38 -0
- backend/tools/tencent_firewall.py +300 -0
- backend/tools/threat_intel.py +732 -0
- backend/tools/trust_checker.py +76 -0
- backend/utils/__init__.py +5 -0
- backend/utils/config_loader.py +164 -0
- backend/utils/env.py +75 -0
- backend/utils/logger.py +150 -0
- backend/utils/text.py +32 -0
- secagentx-3.0.0.dist-info/METADATA +325 -0
- secagentx-3.0.0.dist-info/RECORD +182 -0
- secagentx-3.0.0.dist-info/WHEEL +5 -0
- secagentx-3.0.0.dist-info/entry_points.txt +2 -0
- secagentx-3.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "secagentx-frontend",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite",
|
|
8
|
+
"build": "vite build",
|
|
9
|
+
"preview": "vite preview",
|
|
10
|
+
"test": "vitest run",
|
|
11
|
+
"test:watch": "vitest",
|
|
12
|
+
"test:coverage": "vitest run --coverage",
|
|
13
|
+
"test:e2e": "playwright test",
|
|
14
|
+
"test:e2e:ui": "playwright test --ui"
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@vicons/ionicons5": "^0.13.0",
|
|
18
|
+
"echarts": "^6.1.0",
|
|
19
|
+
"marked": "^12.0.0",
|
|
20
|
+
"naive-ui": "^2.38.0",
|
|
21
|
+
"pinia": "^2.1.0",
|
|
22
|
+
"vue": "^3.4.0",
|
|
23
|
+
"vue-router": "^4.3.0"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@playwright/test": "^1.62.0",
|
|
27
|
+
"@vitejs/plugin-vue": "^6.0.8",
|
|
28
|
+
"@vue/test-utils": "^2.4.11",
|
|
29
|
+
"jsdom": "^29.1.1",
|
|
30
|
+
"vite": "^8.2.2",
|
|
31
|
+
"vitest": "^4.1.10"
|
|
32
|
+
},
|
|
33
|
+
"overrides": {
|
|
34
|
+
"nanoid": "^3.3.18",
|
|
35
|
+
"postcss": "^8.5.23"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<n-config-provider :theme="customTheme" :locale="zhCN" :date-locale="dateZhCN">
|
|
3
|
+
<n-message-provider>
|
|
4
|
+
<n-notification-provider>
|
|
5
|
+
<n-dialog-provider>
|
|
6
|
+
<n-layout position="absolute" style="height: 100vh; background: var(--bg-primary);">
|
|
7
|
+
<!-- 顶部导航栏 -->
|
|
8
|
+
<n-layout-header bordered style="height: var(--header-height); display: flex; align-items: center; padding: 0 20px; background: var(--bg-card); border-bottom: 1px solid var(--border-primary);">
|
|
9
|
+
<!-- Logo 区域 -->
|
|
10
|
+
<div style="display: flex; align-items: center; gap: 10px;">
|
|
11
|
+
<div style="width: 28px; height: 28px; border-radius: 8px; background: var(--accent); display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 14px; color: white; letter-spacing: 1px;">
|
|
12
|
+
SX
|
|
13
|
+
</div>
|
|
14
|
+
<span style="color: var(--accent); font-size: 16px; font-weight: 700; letter-spacing: 1.5px;">SecAgentX</span>
|
|
15
|
+
<span style="color: var(--text-muted); font-size: 11px; font-weight: 400; padding-left: 10px; border-left: 1px solid var(--border-primary);">AI 安全智能体</span>
|
|
16
|
+
</div>
|
|
17
|
+
<div style="flex:1" />
|
|
18
|
+
<!-- 右侧状态区 -->
|
|
19
|
+
<template v-if="!isLoginPage">
|
|
20
|
+
<!-- 连接状态指示灯 - 使用 store 的统一状态 -->
|
|
21
|
+
<div style="display: flex; align-items: center; gap: 6px; margin-right: 16px;">
|
|
22
|
+
<div :style="{
|
|
23
|
+
width: '7px', height: '7px', borderRadius: '50%',
|
|
24
|
+
background: chatStore.wsConnected ? 'var(--success)' : 'var(--error)',
|
|
25
|
+
boxShadow: chatStore.wsConnected ? '0 0 8px rgba(34,197,94,0.5)' : 'none',
|
|
26
|
+
animation: chatStore.wsConnected ? 'pulse-dot 2s infinite' : 'none',
|
|
27
|
+
}"></div>
|
|
28
|
+
<span style="color: var(--text-muted); font-size: 11px; font-weight: 500;">
|
|
29
|
+
{{ chatStore.wsConnected ? '已连接' : '未连接' }}
|
|
30
|
+
</span>
|
|
31
|
+
</div>
|
|
32
|
+
<!-- 用户信息 -->
|
|
33
|
+
<div v-if="currentUser" style="display: flex; align-items: center; gap: 8px; padding: 4px 12px 4px 4px; border-radius: var(--radius-full); background: var(--bg-elevated); border: 1px solid var(--border-primary);">
|
|
34
|
+
<div style="width: 26px; height: 26px; border-radius: 50%; background: linear-gradient(135deg, var(--accent), var(--accent-hover)); display: flex; align-items: center; justify-content: center; color: white; font-size: 11px; font-weight: 700;">
|
|
35
|
+
{{ (currentUser.display_name || currentUser.username).charAt(0).toUpperCase() }}
|
|
36
|
+
</div>
|
|
37
|
+
<span style="color: var(--text-secondary); font-size: 12px; font-weight: 500; line-height: 1;">
|
|
38
|
+
{{ currentUser.display_name || currentUser.username }}
|
|
39
|
+
<span style="color: var(--text-muted); font-weight: 400; font-size: 10px; margin-left: 4px;">{{ currentUser.role }}</span>
|
|
40
|
+
</span>
|
|
41
|
+
</div>
|
|
42
|
+
<n-button text size="small" @click="handleLogout" style="color: var(--text-muted); font-size: 11px; margin-left: 4px;">
|
|
43
|
+
退出
|
|
44
|
+
</n-button>
|
|
45
|
+
</template>
|
|
46
|
+
</n-layout-header>
|
|
47
|
+
|
|
48
|
+
<!-- 主体区域(登录页不渲染侧边栏菜单,避免"点了跳不走"的困惑) -->
|
|
49
|
+
<n-layout v-if="!isLoginPage" position="absolute" style="top: var(--header-height); bottom: 0; background: var(--bg-primary);" has-sider>
|
|
50
|
+
<n-layout-sider bordered :width="220" :collapsed-width="64" show-trigger="bar" style="background: var(--bg-card); border-right: 1px solid var(--border-primary);">
|
|
51
|
+
<n-menu :value="currentRoute" :options="menuOptions" @update:value="onMenuChange" style="background: var(--bg-card); padding-top: 4px;" />
|
|
52
|
+
</n-layout-sider>
|
|
53
|
+
<n-layout style="background: var(--bg-primary);">
|
|
54
|
+
<!-- 页面过渡动画 - 只用透明度,杜绝 out-in 白帧 -->
|
|
55
|
+
<router-view v-slot="{ Component, route: r }">
|
|
56
|
+
<transition name="fade" mode="default">
|
|
57
|
+
<component :is="Component" :key="r.path" />
|
|
58
|
+
</transition>
|
|
59
|
+
</router-view>
|
|
60
|
+
</n-layout>
|
|
61
|
+
</n-layout>
|
|
62
|
+
<!-- 登录页:主体直接渲染登录视图 -->
|
|
63
|
+
<n-layout v-else position="absolute" style="top: 0; bottom: 0; background: var(--bg-primary);">
|
|
64
|
+
<router-view />
|
|
65
|
+
</n-layout>
|
|
66
|
+
</n-layout>
|
|
67
|
+
</n-dialog-provider>
|
|
68
|
+
</n-notification-provider>
|
|
69
|
+
</n-message-provider>
|
|
70
|
+
</n-config-provider>
|
|
71
|
+
</template>
|
|
72
|
+
|
|
73
|
+
<script setup>
|
|
74
|
+
import { ref, computed, h, onMounted, onUnmounted, watch } from 'vue'
|
|
75
|
+
import { useRouter, useRoute } from 'vue-router'
|
|
76
|
+
import { darkTheme, zhCN, dateZhCN, NConfigProvider, useMessage } from 'naive-ui'
|
|
77
|
+
import { useChatStore } from './stores/chat.js'
|
|
78
|
+
import { buildApiUrl } from './utils/http.js'
|
|
79
|
+
import {
|
|
80
|
+
GridOutline,
|
|
81
|
+
ChatbubblesOutline,
|
|
82
|
+
CubeOutline,
|
|
83
|
+
WarningOutline,
|
|
84
|
+
GitNetworkOutline,
|
|
85
|
+
ShieldCheckmarkOutline,
|
|
86
|
+
BugOutline,
|
|
87
|
+
DocumentTextOutline,
|
|
88
|
+
SettingsOutline,
|
|
89
|
+
PeopleOutline,
|
|
90
|
+
} from '@vicons/ionicons5'
|
|
91
|
+
|
|
92
|
+
const router = useRouter()
|
|
93
|
+
const route = useRoute()
|
|
94
|
+
const chatStore = useChatStore()
|
|
95
|
+
|
|
96
|
+
// useMessage 降级(provider 在子组件中)
|
|
97
|
+
let message
|
|
98
|
+
try {
|
|
99
|
+
message = useMessage()
|
|
100
|
+
} catch (e) {
|
|
101
|
+
message = { error: console.warn, success: console.log, warning: console.warn, info: console.log }
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const isLoginPage = computed(() => route.path === '/login')
|
|
105
|
+
const currentUser = ref(null)
|
|
106
|
+
const userPermissions = ref([])
|
|
107
|
+
|
|
108
|
+
const currentRoute = computed(() => route.path)
|
|
109
|
+
|
|
110
|
+
function loadUser() {
|
|
111
|
+
try {
|
|
112
|
+
const u = localStorage.getItem('secagentx_user')
|
|
113
|
+
if (u) currentUser.value = JSON.parse(u)
|
|
114
|
+
const p = localStorage.getItem('secagentx_permissions')
|
|
115
|
+
if (p) userPermissions.value = JSON.parse(p)
|
|
116
|
+
} catch (e) {
|
|
117
|
+
currentUser.value = null
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async function fetchPermissions() {
|
|
122
|
+
try {
|
|
123
|
+
const token = localStorage.getItem('secagentx_token')
|
|
124
|
+
if (!token) return
|
|
125
|
+
const resp = await fetch(buildApiUrl('/api/users/me'), {
|
|
126
|
+
headers: { 'Authorization': `Bearer ${token}` }
|
|
127
|
+
})
|
|
128
|
+
if (resp.ok) {
|
|
129
|
+
const data = await resp.json()
|
|
130
|
+
if (data.permissions) {
|
|
131
|
+
userPermissions.value = data.permissions
|
|
132
|
+
localStorage.setItem('secagentx_permissions', JSON.stringify(data.permissions))
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
} catch (e) { /* ignore */ }
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function hasPermission(perm) {
|
|
139
|
+
return userPermissions.value.includes(perm)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
loadUser()
|
|
143
|
+
|
|
144
|
+
// 设计系统主题 — 复用 tokens.css 变量
|
|
145
|
+
const customTheme = {
|
|
146
|
+
...darkTheme,
|
|
147
|
+
common: {
|
|
148
|
+
...darkTheme.common,
|
|
149
|
+
primaryColor: '#dc2626',
|
|
150
|
+
primaryColorHover: '#ef4444',
|
|
151
|
+
primaryColorPressed: '#b91c1c',
|
|
152
|
+
primaryColorSuppl: '#dc2626',
|
|
153
|
+
bodyColor: '#0f1117',
|
|
154
|
+
cardColor: '#171923',
|
|
155
|
+
modalColor: '#171923',
|
|
156
|
+
popoverColor: '#171923',
|
|
157
|
+
tableColor: '#171923',
|
|
158
|
+
borderColor: '#2a2d38',
|
|
159
|
+
dividerColor: '#2a2d38',
|
|
160
|
+
actionColor: '#171923',
|
|
161
|
+
tabColor: '#171923',
|
|
162
|
+
inputColor: '#171923',
|
|
163
|
+
inputColorDisabled: '#171923',
|
|
164
|
+
hoverColor: '#1f2230',
|
|
165
|
+
closeColor: '#64748b',
|
|
166
|
+
closeColorHover: '#e2e8f0',
|
|
167
|
+
textColor1: '#f1f5f9',
|
|
168
|
+
textColor2: '#cbd5e1',
|
|
169
|
+
textColor3: '#94a3b8',
|
|
170
|
+
textColorDisabled: '#64748b',
|
|
171
|
+
placeholderColor: '#475569',
|
|
172
|
+
invertedColor: '#0f1117',
|
|
173
|
+
progressRailColor: '#2a2d38',
|
|
174
|
+
railColor: '#2a2d38',
|
|
175
|
+
fontWeightStrong: '600',
|
|
176
|
+
},
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// 带 SVG 图标的菜单 — 使用 ionicons5 渲染
|
|
180
|
+
function renderIcon(icon) {
|
|
181
|
+
return () => h(icon, { style: 'width:18px;height:18px;' })
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const menuOptions = computed(() => {
|
|
185
|
+
const items = [
|
|
186
|
+
{ label: '总览', key: '/dashboard', icon: renderIcon(GridOutline) },
|
|
187
|
+
{ label: '对话', key: '/', icon: renderIcon(ChatbubblesOutline) },
|
|
188
|
+
{ label: 'Agent 状态', key: '/agents', icon: renderIcon(CubeOutline) },
|
|
189
|
+
{ label: '事件', key: '/events', icon: renderIcon(WarningOutline) },
|
|
190
|
+
{ label: 'ATT&CK 知识库', key: '/knowledge/mitre', icon: renderIcon(GitNetworkOutline) },
|
|
191
|
+
{ label: 'OWASP 知识库', key: '/knowledge/owasp', icon: renderIcon(ShieldCheckmarkOutline) },
|
|
192
|
+
{ label: 'CVE 漏洞库', key: '/knowledge/cve', icon: renderIcon(BugOutline) },
|
|
193
|
+
{ label: '检测规则', key: '/knowledge/rules', icon: renderIcon(DocumentTextOutline) },
|
|
194
|
+
]
|
|
195
|
+
if (hasPermission('admin:users')) {
|
|
196
|
+
items.push({ label: '系统设置', key: '/settings', icon: renderIcon(SettingsOutline) })
|
|
197
|
+
items.push({ label: '用户管理', key: '/users', icon: renderIcon(PeopleOutline) })
|
|
198
|
+
}
|
|
199
|
+
return items
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
function onMenuChange(key) {
|
|
203
|
+
router.push(key)
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function handleLogout() {
|
|
207
|
+
chatStore.disconnectWebSocket()
|
|
208
|
+
localStorage.removeItem('secagentx_token')
|
|
209
|
+
localStorage.removeItem('secagentx_user')
|
|
210
|
+
localStorage.removeItem('secagentx_permissions')
|
|
211
|
+
router.push('/login')
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// 路由变化时管理 WebSocket 生命周期(登录页断连,其他页连接)
|
|
215
|
+
watch(() => route.path, (newPath) => {
|
|
216
|
+
if (newPath === '/login') {
|
|
217
|
+
chatStore.disconnectWebSocket()
|
|
218
|
+
} else {
|
|
219
|
+
chatStore.connectWebSocket()
|
|
220
|
+
}
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
onMounted(() => {
|
|
224
|
+
const token = localStorage.getItem('secagentx_token')
|
|
225
|
+
if (token) { chatStore.connectWebSocket(); fetchPermissions() }
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
onUnmounted(() => {
|
|
229
|
+
chatStore.disconnectWebSocket()
|
|
230
|
+
})
|
|
231
|
+
</script>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { createApp } from 'vue'
|
|
2
|
+
import { createPinia } from 'pinia'
|
|
3
|
+
import naive from 'naive-ui'
|
|
4
|
+
import router from './router/index.js'
|
|
5
|
+
import App from './App.vue'
|
|
6
|
+
import './styles/tokens.css'
|
|
7
|
+
|
|
8
|
+
const app = createApp(App)
|
|
9
|
+
app.use(createPinia())
|
|
10
|
+
app.use(router)
|
|
11
|
+
app.use(naive)
|
|
12
|
+
app.mount('#app')
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { createRouter, createWebHistory } from 'vue-router'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 路由 base — 运行时自适应(与 http.js 前缀逻辑一致)
|
|
5
|
+
*
|
|
6
|
+
* - OpenIM 集成环境:页面挂在 /secagentx/ 下,路由 base 须为 /secagentx/
|
|
7
|
+
* 否则 SPA 跳转会丢失前缀(如变成 /agents),刷新即被 nginx 拦回 OpenIM 首页
|
|
8
|
+
* - FastAPI 直连:base 为 /
|
|
9
|
+
*/
|
|
10
|
+
function resolveRouterBase() {
|
|
11
|
+
const injected = import.meta.env && import.meta.env.VITE_BASE_PATH
|
|
12
|
+
if (injected) return injected
|
|
13
|
+
if (typeof window !== 'undefined' && window.location.pathname.startsWith('/secagentx/')) {
|
|
14
|
+
return '/secagentx/'
|
|
15
|
+
}
|
|
16
|
+
return '/'
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* 路由守卫:检查是否已登录
|
|
21
|
+
* 未登录时跳转到 /login,并携带目标路径
|
|
22
|
+
*/
|
|
23
|
+
function requireAuth(to, from, next) {
|
|
24
|
+
const token = localStorage.getItem('secagentx_token')
|
|
25
|
+
if (to.meta.requiresAuth !== false && !token) {
|
|
26
|
+
next({ path: '/login', query: { redirect: to.fullPath } })
|
|
27
|
+
} else {
|
|
28
|
+
next()
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const routes = [
|
|
33
|
+
{
|
|
34
|
+
path: '/login',
|
|
35
|
+
name: 'login',
|
|
36
|
+
component: () => import('../views/LoginView.vue'),
|
|
37
|
+
meta: { requiresAuth: false },
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
path: '/',
|
|
41
|
+
name: 'chat',
|
|
42
|
+
component: () => import('../views/ChatView.vue'),
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
path: '/agents',
|
|
46
|
+
name: 'agents',
|
|
47
|
+
component: () => import('../views/AgentsView.vue'),
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
path: '/events',
|
|
51
|
+
name: 'events',
|
|
52
|
+
component: () => import('../views/EventsView.vue'),
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
path: '/knowledge',
|
|
56
|
+
name: 'knowledge',
|
|
57
|
+
component: () => import('../views/KnowledgeView.vue'),
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
path: '/knowledge/mitre',
|
|
61
|
+
name: 'knowledge-mitre',
|
|
62
|
+
component: () => import('../views/KnowledgeView.vue'),
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
path: '/knowledge/owasp',
|
|
66
|
+
name: 'knowledge-owasp',
|
|
67
|
+
component: () => import('../views/KnowledgeView.vue'),
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
path: '/knowledge/cve',
|
|
71
|
+
name: 'knowledge-cve',
|
|
72
|
+
component: () => import('../views/KnowledgeView.vue'),
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
path: '/knowledge/rules',
|
|
76
|
+
name: 'knowledge-rules',
|
|
77
|
+
component: () => import('../views/KnowledgeView.vue'),
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
path: '/attack-chain',
|
|
81
|
+
name: 'attack-chain',
|
|
82
|
+
component: () => import('../views/AttackChainView.vue'),
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
path: '/dashboard',
|
|
86
|
+
name: 'dashboard',
|
|
87
|
+
component: () => import('../views/DashboardView.vue'),
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
path: '/events/:id',
|
|
91
|
+
name: 'event-detail',
|
|
92
|
+
component: () => import('../views/EventDetailView.vue'),
|
|
93
|
+
props: true,
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
path: '/users',
|
|
97
|
+
name: 'users',
|
|
98
|
+
component: () => import('../views/UsersView.vue'),
|
|
99
|
+
meta: { requiresAuth: true },
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
path: '/settings',
|
|
103
|
+
name: 'settings',
|
|
104
|
+
component: () => import('../views/SettingsView.vue'),
|
|
105
|
+
meta: { requiresAuth: true },
|
|
106
|
+
},
|
|
107
|
+
]
|
|
108
|
+
|
|
109
|
+
const router = createRouter({
|
|
110
|
+
history: createWebHistory(resolveRouterBase()),
|
|
111
|
+
routes,
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
// 注册全局路由守卫
|
|
115
|
+
router.beforeEach(requireAuth)
|
|
116
|
+
|
|
117
|
+
export default router
|