mirror of
https://github.com/yyhuni/xingrin.git
synced 2026-01-31 19:53:11 +08:00
Compare commits
5 Commits
v1.3.13-de
...
v1.3.14
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e0abb3ce7b | ||
|
|
d418baaf79 | ||
|
|
f8da408580 | ||
|
|
7b7bbed634 | ||
|
|
08372588a4 |
@@ -48,7 +48,7 @@ ENABLE_COMMAND_LOGGING = getattr(settings, 'ENABLE_COMMAND_LOGGING', True)
|
||||
# 动态并发控制阈值(可在 Django settings 中覆盖)
|
||||
SCAN_CPU_HIGH = getattr(settings, 'SCAN_CPU_HIGH', 90.0) # CPU 高水位(百分比)
|
||||
SCAN_MEM_HIGH = getattr(settings, 'SCAN_MEM_HIGH', 80.0) # 内存高水位(百分比)
|
||||
SCAN_LOAD_CHECK_INTERVAL = getattr(settings, 'SCAN_LOAD_CHECK_INTERVAL', 30) # 负载检查间隔(秒)
|
||||
SCAN_LOAD_CHECK_INTERVAL = getattr(settings, 'SCAN_LOAD_CHECK_INTERVAL', 180) # 负载检查间隔(秒)
|
||||
SCAN_COMMAND_STARTUP_DELAY = getattr(settings, 'SCAN_COMMAND_STARTUP_DELAY', 5) # 命令启动前等待(秒)
|
||||
|
||||
_ACTIVE_COMMANDS = 0
|
||||
@@ -74,7 +74,7 @@ def _wait_for_system_load() -> None:
|
||||
return
|
||||
|
||||
logger.info(
|
||||
"系统负载较高,暂缓启动: cpu=%.1f%% (阈值 %.1f%%), mem=%.1f%% (阈值 %.1f%%)",
|
||||
"系统负载较高,任务将排队执行,防止oom: cpu=%.1f%% (阈值 %.1f%%), mem=%.1f%% (阈值 %.1f%%)",
|
||||
cpu,
|
||||
SCAN_CPU_HIGH,
|
||||
mem,
|
||||
|
||||
187
frontend/mock/data/directories.ts
Normal file
187
frontend/mock/data/directories.ts
Normal file
@@ -0,0 +1,187 @@
|
||||
import type { Directory, DirectoryListResponse } from '@/types/directory.types'
|
||||
|
||||
export const mockDirectories: Directory[] = [
|
||||
{
|
||||
id: 1,
|
||||
url: 'https://acme.com/admin',
|
||||
status: 200,
|
||||
contentLength: 12345,
|
||||
words: 1234,
|
||||
lines: 89,
|
||||
contentType: 'text/html',
|
||||
duration: 0.234,
|
||||
websiteUrl: 'https://acme.com',
|
||||
createdAt: '2024-12-28T10:00:00Z',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
url: 'https://acme.com/api',
|
||||
status: 301,
|
||||
contentLength: 0,
|
||||
words: 0,
|
||||
lines: 0,
|
||||
contentType: 'text/html',
|
||||
duration: 0.056,
|
||||
websiteUrl: 'https://acme.com',
|
||||
createdAt: '2024-12-28T10:01:00Z',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
url: 'https://acme.com/login',
|
||||
status: 200,
|
||||
contentLength: 8765,
|
||||
words: 567,
|
||||
lines: 45,
|
||||
contentType: 'text/html',
|
||||
duration: 0.189,
|
||||
websiteUrl: 'https://acme.com',
|
||||
createdAt: '2024-12-28T10:02:00Z',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
url: 'https://acme.com/dashboard',
|
||||
status: 302,
|
||||
contentLength: 0,
|
||||
words: 0,
|
||||
lines: 0,
|
||||
contentType: 'text/html',
|
||||
duration: 0.078,
|
||||
websiteUrl: 'https://acme.com',
|
||||
createdAt: '2024-12-28T10:03:00Z',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
url: 'https://acme.com/static/js/app.js',
|
||||
status: 200,
|
||||
contentLength: 456789,
|
||||
words: 12345,
|
||||
lines: 5678,
|
||||
contentType: 'application/javascript',
|
||||
duration: 0.345,
|
||||
websiteUrl: 'https://acme.com',
|
||||
createdAt: '2024-12-28T10:04:00Z',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
url: 'https://acme.com/.git/config',
|
||||
status: 200,
|
||||
contentLength: 234,
|
||||
words: 45,
|
||||
lines: 12,
|
||||
contentType: 'text/plain',
|
||||
duration: 0.023,
|
||||
websiteUrl: 'https://acme.com',
|
||||
createdAt: '2024-12-28T10:05:00Z',
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
url: 'https://acme.com/backup.zip',
|
||||
status: 200,
|
||||
contentLength: 12345678,
|
||||
words: null,
|
||||
lines: null,
|
||||
contentType: 'application/zip',
|
||||
duration: 1.234,
|
||||
websiteUrl: 'https://acme.com',
|
||||
createdAt: '2024-12-28T10:06:00Z',
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
url: 'https://acme.com/robots.txt',
|
||||
status: 200,
|
||||
contentLength: 567,
|
||||
words: 89,
|
||||
lines: 23,
|
||||
contentType: 'text/plain',
|
||||
duration: 0.034,
|
||||
websiteUrl: 'https://acme.com',
|
||||
createdAt: '2024-12-28T10:07:00Z',
|
||||
},
|
||||
{
|
||||
id: 9,
|
||||
url: 'https://api.acme.com/v1/health',
|
||||
status: 200,
|
||||
contentLength: 45,
|
||||
words: 5,
|
||||
lines: 1,
|
||||
contentType: 'application/json',
|
||||
duration: 0.012,
|
||||
websiteUrl: 'https://api.acme.com',
|
||||
createdAt: '2024-12-28T10:08:00Z',
|
||||
},
|
||||
{
|
||||
id: 10,
|
||||
url: 'https://api.acme.com/swagger-ui.html',
|
||||
status: 200,
|
||||
contentLength: 23456,
|
||||
words: 1234,
|
||||
lines: 234,
|
||||
contentType: 'text/html',
|
||||
duration: 0.267,
|
||||
websiteUrl: 'https://api.acme.com',
|
||||
createdAt: '2024-12-28T10:09:00Z',
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
url: 'https://techstart.io/wp-admin',
|
||||
status: 302,
|
||||
contentLength: 0,
|
||||
words: 0,
|
||||
lines: 0,
|
||||
contentType: 'text/html',
|
||||
duration: 0.089,
|
||||
websiteUrl: 'https://techstart.io',
|
||||
createdAt: '2024-12-26T08:45:00Z',
|
||||
},
|
||||
{
|
||||
id: 12,
|
||||
url: 'https://techstart.io/wp-login.php',
|
||||
status: 200,
|
||||
contentLength: 4567,
|
||||
words: 234,
|
||||
lines: 78,
|
||||
contentType: 'text/html',
|
||||
duration: 0.156,
|
||||
websiteUrl: 'https://techstart.io',
|
||||
createdAt: '2024-12-26T08:46:00Z',
|
||||
},
|
||||
]
|
||||
|
||||
export function getMockDirectories(params?: {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
filter?: string
|
||||
targetId?: number
|
||||
scanId?: number
|
||||
}): DirectoryListResponse {
|
||||
const page = params?.page || 1
|
||||
const pageSize = params?.pageSize || 10
|
||||
const filter = params?.filter?.toLowerCase() || ''
|
||||
|
||||
let filtered = mockDirectories
|
||||
|
||||
if (filter) {
|
||||
filtered = filtered.filter(
|
||||
d =>
|
||||
d.url.toLowerCase().includes(filter) ||
|
||||
d.contentType.toLowerCase().includes(filter)
|
||||
)
|
||||
}
|
||||
|
||||
const total = filtered.length
|
||||
const totalPages = Math.ceil(total / pageSize)
|
||||
const start = (page - 1) * pageSize
|
||||
const results = filtered.slice(start, start + pageSize)
|
||||
|
||||
return {
|
||||
results,
|
||||
total,
|
||||
page,
|
||||
pageSize,
|
||||
totalPages,
|
||||
}
|
||||
}
|
||||
|
||||
export function getMockDirectoryById(id: number): Directory | undefined {
|
||||
return mockDirectories.find(d => d.id === id)
|
||||
}
|
||||
593
frontend/mock/data/fingerprints.ts
Normal file
593
frontend/mock/data/fingerprints.ts
Normal file
@@ -0,0 +1,593 @@
|
||||
import type {
|
||||
EholeFingerprint,
|
||||
GobyFingerprint,
|
||||
WappalyzerFingerprint,
|
||||
FingersFingerprint,
|
||||
FingerPrintHubFingerprint,
|
||||
ARLFingerprint,
|
||||
FingerprintStats,
|
||||
} from '@/types/fingerprint.types'
|
||||
import type { PaginatedResponse } from '@/types/api-response.types'
|
||||
|
||||
// ==================== EHole 指纹数据(真实数据示例)====================
|
||||
export const mockEholeFingerprints: EholeFingerprint[] = [
|
||||
{
|
||||
id: 1,
|
||||
cms: '致远OA',
|
||||
method: 'keyword',
|
||||
location: 'body',
|
||||
keyword: ['/seeyon/USER-DATA/IMAGES/LOGIN/login.gif'],
|
||||
isImportant: true,
|
||||
type: 'oa',
|
||||
createdAt: '2024-12-20T10:00:00Z',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
cms: '通达OA',
|
||||
method: 'keyword',
|
||||
location: 'body',
|
||||
keyword: ['/static/images/tongda.ico'],
|
||||
isImportant: true,
|
||||
type: 'oa',
|
||||
createdAt: '2024-12-20T10:01:00Z',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
cms: 'Nexus Repository Manager',
|
||||
method: 'keyword',
|
||||
location: 'title',
|
||||
keyword: ['Nexus Repository Manager'],
|
||||
isImportant: true,
|
||||
type: 'cloud',
|
||||
createdAt: '2024-12-20T10:02:00Z',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
cms: '禅道 zentao',
|
||||
method: 'keyword',
|
||||
location: 'title',
|
||||
keyword: ['Welcome to use zentao'],
|
||||
isImportant: true,
|
||||
type: 'oa',
|
||||
createdAt: '2024-12-20T10:03:00Z',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
cms: 'Kibana',
|
||||
method: 'keyword',
|
||||
location: 'title',
|
||||
keyword: ['Kibana'],
|
||||
isImportant: true,
|
||||
type: 'cloud',
|
||||
createdAt: '2024-12-20T10:04:00Z',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
cms: 'Spring env',
|
||||
method: 'keyword',
|
||||
location: 'body',
|
||||
keyword: ['Whitelabel Error Page'],
|
||||
isImportant: true,
|
||||
type: 'framework',
|
||||
createdAt: '2024-12-20T10:05:00Z',
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
cms: '泛微OA',
|
||||
method: 'keyword',
|
||||
location: 'header',
|
||||
keyword: ['ecology_JSessionid'],
|
||||
isImportant: true,
|
||||
type: 'oa',
|
||||
createdAt: '2024-12-20T10:06:00Z',
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
cms: '用友NC',
|
||||
method: 'keyword',
|
||||
location: 'body',
|
||||
keyword: ['UFIDA', '/nc/servlet/nc.ui.iufo.login.Index'],
|
||||
isImportant: true,
|
||||
type: 'oa',
|
||||
createdAt: '2024-12-20T10:07:00Z',
|
||||
},
|
||||
]
|
||||
|
||||
// ==================== Goby 指纹数据(真实数据示例)====================
|
||||
export const mockGobyFingerprints: GobyFingerprint[] = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'WebSphere-App-Server',
|
||||
logic: '((a||b) &&c&&d) || (e&&f&&g)',
|
||||
rule: [
|
||||
{ label: 'a', feature: 'Server: WebSphere Application Server', is_equal: true },
|
||||
{ label: 'b', feature: 'IBM WebSphere Application Server', is_equal: true },
|
||||
{ label: 'c', feature: 'couchdb', is_equal: false },
|
||||
{ label: 'd', feature: 'drupal', is_equal: false },
|
||||
{ label: 'e', feature: 'Server: WebSphere Application Server', is_equal: true },
|
||||
{ label: 'f', feature: 'couchdb', is_equal: false },
|
||||
{ label: 'g', feature: 'drupal', is_equal: false },
|
||||
],
|
||||
createdAt: '2024-12-20T10:00:00Z',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'Wing-FTP-Server',
|
||||
logic: 'a||b||c||d',
|
||||
rule: [
|
||||
{ label: 'a', feature: 'Server: Wing FTP Server', is_equal: true },
|
||||
{ label: 'b', feature: 'Server: Wing FTP Server', is_equal: true },
|
||||
{ label: 'c', feature: '/help_javascript.htm', is_equal: true },
|
||||
{ label: 'd', feature: 'Wing FTP Server', is_equal: true },
|
||||
],
|
||||
createdAt: '2024-12-20T10:01:00Z',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Fortinet-sslvpn',
|
||||
logic: 'a&&b',
|
||||
rule: [
|
||||
{ label: 'a', feature: 'fgt_lang', is_equal: true },
|
||||
{ label: 'b', feature: '/sslvpn/portal.html', is_equal: true },
|
||||
],
|
||||
createdAt: '2024-12-20T10:02:00Z',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'D-link-DSL-2640B',
|
||||
logic: 'a||b',
|
||||
rule: [
|
||||
{ label: 'a', feature: 'Product : DSL-2640B', is_equal: true },
|
||||
{ label: 'b', feature: 'D-Link DSL-2640B', is_equal: true },
|
||||
],
|
||||
createdAt: '2024-12-20T10:03:00Z',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'Kedacom-NVR',
|
||||
logic: 'a|| (b&&c) ||d',
|
||||
rule: [
|
||||
{ label: 'a', feature: 'NVR Station Web', is_equal: true },
|
||||
{ label: 'b', feature: 'location="index_cn.htm";', is_equal: true },
|
||||
{ label: 'c', feature: 'if(syslan == "zh-cn"', is_equal: true },
|
||||
{ label: 'd', feature: 'WMS browse NVR', is_equal: true },
|
||||
],
|
||||
createdAt: '2024-12-20T10:04:00Z',
|
||||
},
|
||||
]
|
||||
|
||||
// ==================== Wappalyzer 指纹数据(真实数据示例)====================
|
||||
export const mockWappalyzerFingerprints: WappalyzerFingerprint[] = [
|
||||
{
|
||||
id: 1,
|
||||
name: '1C-Bitrix',
|
||||
cats: [1, 6],
|
||||
cookies: { bitrix_sm_guest_id: '', bitrix_sm_last_ip: '', bitrix_sm_sale_uid: '' },
|
||||
headers: { 'set-cookie': 'bitrix_', 'x-powered-cms': 'bitrix site manager' },
|
||||
scriptSrc: ['bitrix(?:\\.info/|/js/main/core)'],
|
||||
js: [],
|
||||
implies: ['PHP'],
|
||||
meta: {},
|
||||
html: [],
|
||||
description: '1C-Bitrix is a system of web project management.',
|
||||
website: 'https://www.1c-bitrix.ru',
|
||||
cpe: '',
|
||||
createdAt: '2024-12-20T10:00:00Z',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'React',
|
||||
cats: [12],
|
||||
cookies: {},
|
||||
headers: {},
|
||||
scriptSrc: ['react(?:-dom)?(?:\\.min)?\\.js'],
|
||||
js: ['React.version'],
|
||||
implies: [],
|
||||
meta: {},
|
||||
html: ['data-reactroot'],
|
||||
description: 'React is a JavaScript library for building user interfaces.',
|
||||
website: 'https://reactjs.org',
|
||||
cpe: 'cpe:/a:facebook:react',
|
||||
createdAt: '2024-12-20T10:01:00Z',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Vue.js',
|
||||
cats: [12],
|
||||
cookies: {},
|
||||
headers: {},
|
||||
scriptSrc: ['vue(?:\\.min)?\\.js'],
|
||||
js: ['Vue.version'],
|
||||
implies: [],
|
||||
meta: {},
|
||||
html: ['data-v-'],
|
||||
description: 'Vue.js is a progressive JavaScript framework.',
|
||||
website: 'https://vuejs.org',
|
||||
cpe: 'cpe:/a:vuejs:vue',
|
||||
createdAt: '2024-12-20T10:02:00Z',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'nginx',
|
||||
cats: [22],
|
||||
cookies: {},
|
||||
headers: { server: 'nginx(?:/([\\d.]+))?\\;version:\\1' },
|
||||
scriptSrc: [],
|
||||
js: [],
|
||||
implies: [],
|
||||
meta: {},
|
||||
html: [],
|
||||
description: 'nginx is a web server.',
|
||||
website: 'http://nginx.org/en',
|
||||
cpe: 'cpe:/a:nginx:nginx',
|
||||
createdAt: '2024-12-20T10:03:00Z',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'WordPress',
|
||||
cats: [1, 11],
|
||||
cookies: {},
|
||||
headers: { 'x-pingback': '/xmlrpc\\.php$' },
|
||||
scriptSrc: ['/wp-(?:content|includes)/'],
|
||||
js: [],
|
||||
implies: ['PHP', 'MySQL'],
|
||||
meta: { generator: ['WordPress(?: ([\\d.]+))?\\;version:\\1'] },
|
||||
html: ['<link rel=["\']stylesheet["\'] [^>]+/wp-(?:content|includes)/'],
|
||||
description: 'WordPress is a free and open-source CMS.',
|
||||
website: 'https://wordpress.org',
|
||||
cpe: 'cpe:/a:wordpress:wordpress',
|
||||
createdAt: '2024-12-20T10:04:00Z',
|
||||
},
|
||||
]
|
||||
|
||||
// ==================== Fingers 指纹数据(真实数据示例)====================
|
||||
export const mockFingersFingerprints: FingersFingerprint[] = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'jenkins',
|
||||
link: '',
|
||||
rule: [
|
||||
{
|
||||
favicon_hash: ['81586312'],
|
||||
body: 'Jenkins',
|
||||
header: 'X-Jenkins',
|
||||
},
|
||||
],
|
||||
tag: ['cloud'],
|
||||
focus: true,
|
||||
defaultPort: [8080],
|
||||
createdAt: '2024-12-20T10:00:00Z',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'gitlab',
|
||||
link: '',
|
||||
rule: [
|
||||
{
|
||||
favicon_hash: ['516963061', '1278323681'],
|
||||
body: 'GitLab',
|
||||
header: '_gitlab_session',
|
||||
},
|
||||
],
|
||||
tag: ['cloud'],
|
||||
focus: true,
|
||||
defaultPort: [80, 443],
|
||||
createdAt: '2024-12-20T10:01:00Z',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'nacos',
|
||||
link: '',
|
||||
rule: [
|
||||
{
|
||||
body: '<title>Nacos</title>',
|
||||
send_data: '/nacos/',
|
||||
},
|
||||
],
|
||||
tag: ['cloud'],
|
||||
focus: true,
|
||||
defaultPort: [8848],
|
||||
createdAt: '2024-12-20T10:02:00Z',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'elasticsearch',
|
||||
link: '',
|
||||
rule: [
|
||||
{
|
||||
body: '"cluster_name" : "elasticsearch"',
|
||||
vuln: 'elasticsearch_unauth',
|
||||
},
|
||||
],
|
||||
tag: ['cloud'],
|
||||
focus: true,
|
||||
defaultPort: [9200],
|
||||
createdAt: '2024-12-20T10:03:00Z',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'zabbix',
|
||||
link: '',
|
||||
rule: [
|
||||
{
|
||||
favicon_hash: ['892542951'],
|
||||
body: 'images/general/zabbix.ico',
|
||||
header: 'zbx_sessionid',
|
||||
send_data: '/zabbix',
|
||||
},
|
||||
],
|
||||
tag: ['cloud'],
|
||||
focus: true,
|
||||
defaultPort: [80, 443],
|
||||
createdAt: '2024-12-20T10:04:00Z',
|
||||
},
|
||||
]
|
||||
|
||||
// ==================== FingerPrintHub 指纹数据(真实数据示例)====================
|
||||
export const mockFingerPrintHubFingerprints: FingerPrintHubFingerprint[] = [
|
||||
{
|
||||
id: 1,
|
||||
fpId: 'apache-tomcat',
|
||||
name: 'Apache Tomcat',
|
||||
author: 'pdteam',
|
||||
tags: 'tech,apache,tomcat',
|
||||
severity: 'info',
|
||||
metadata: {
|
||||
product: 'tomcat',
|
||||
vendor: 'apache',
|
||||
verified: true,
|
||||
shodan_query: 'http.favicon.hash:"-297069493"',
|
||||
fofa_query: 'app="Apache-Tomcat"',
|
||||
},
|
||||
http: [
|
||||
{
|
||||
method: 'GET',
|
||||
path: '/',
|
||||
matchers: [
|
||||
{ type: 'word', part: 'body', words: ['Apache Tomcat'] },
|
||||
{ type: 'status', status: [200] },
|
||||
],
|
||||
},
|
||||
],
|
||||
sourceFile: 'http/technologies/apache/apache-tomcat.yaml',
|
||||
createdAt: '2024-12-20T10:00:00Z',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
fpId: 'nginx-detect',
|
||||
name: 'Nginx Server',
|
||||
author: 'pdteam',
|
||||
tags: 'tech,nginx',
|
||||
severity: 'info',
|
||||
metadata: {
|
||||
product: 'nginx',
|
||||
vendor: 'nginx',
|
||||
verified: true,
|
||||
},
|
||||
http: [
|
||||
{
|
||||
method: 'GET',
|
||||
path: '/',
|
||||
matchers: [
|
||||
{ type: 'regex', part: 'header', regex: ['[Nn]ginx'] },
|
||||
],
|
||||
extractors: [
|
||||
{ type: 'regex', part: 'header', regex: ['nginx/([\\d.]+)'], group: 1 },
|
||||
],
|
||||
},
|
||||
],
|
||||
sourceFile: 'http/technologies/nginx/nginx-version.yaml',
|
||||
createdAt: '2024-12-20T10:01:00Z',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
fpId: 'spring-boot-detect',
|
||||
name: 'Spring Boot',
|
||||
author: 'pdteam',
|
||||
tags: 'tech,spring,java',
|
||||
severity: 'info',
|
||||
metadata: {
|
||||
product: 'spring-boot',
|
||||
vendor: 'vmware',
|
||||
verified: true,
|
||||
},
|
||||
http: [
|
||||
{
|
||||
method: 'GET',
|
||||
path: '/',
|
||||
matchers: [
|
||||
{ type: 'word', part: 'body', words: ['Whitelabel Error Page'] },
|
||||
],
|
||||
},
|
||||
],
|
||||
sourceFile: 'http/technologies/spring/spring-boot.yaml',
|
||||
createdAt: '2024-12-20T10:02:00Z',
|
||||
},
|
||||
]
|
||||
|
||||
// ==================== ARL 指纹数据(真实数据示例)====================
|
||||
export const mockARLFingerprints: ARLFingerprint[] = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Shiro',
|
||||
rule: 'header="rememberMe="',
|
||||
createdAt: '2024-12-20T10:00:00Z',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'ThinkPHP',
|
||||
rule: 'body="ThinkPHP" || header="ThinkPHP"',
|
||||
createdAt: '2024-12-20T10:01:00Z',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'Fastjson',
|
||||
rule: 'body="fastjson" || body="com.alibaba.fastjson"',
|
||||
createdAt: '2024-12-20T10:02:00Z',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'Weblogic',
|
||||
rule: 'body="WebLogic" || header="WebLogic" || body="bea_wls_internal"',
|
||||
createdAt: '2024-12-20T10:03:00Z',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'JBoss',
|
||||
rule: 'body="JBoss" || header="JBoss" || body="jboss.css"',
|
||||
createdAt: '2024-12-20T10:04:00Z',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: 'Struts2',
|
||||
rule: 'body=".action" || body="struts"',
|
||||
createdAt: '2024-12-20T10:05:00Z',
|
||||
},
|
||||
]
|
||||
|
||||
// ==================== 统计数据 ====================
|
||||
export const mockFingerprintStats: FingerprintStats = {
|
||||
ehole: 1892,
|
||||
goby: 4567,
|
||||
wappalyzer: 3456,
|
||||
fingers: 2345,
|
||||
fingerprinthub: 8901,
|
||||
arl: 1234,
|
||||
}
|
||||
|
||||
// ==================== 查询函数 ====================
|
||||
export function getMockEholeFingerprints(params?: {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
filter?: string
|
||||
}): PaginatedResponse<EholeFingerprint> {
|
||||
const page = params?.page || 1
|
||||
const pageSize = params?.pageSize || 10
|
||||
const filter = params?.filter?.toLowerCase() || ''
|
||||
|
||||
let filtered = mockEholeFingerprints
|
||||
if (filter) {
|
||||
filtered = filtered.filter(f => f.cms.toLowerCase().includes(filter))
|
||||
}
|
||||
|
||||
const total = filtered.length
|
||||
const totalPages = Math.ceil(total / pageSize)
|
||||
const start = (page - 1) * pageSize
|
||||
const results = filtered.slice(start, start + pageSize)
|
||||
|
||||
return { results, total, page, pageSize, totalPages }
|
||||
}
|
||||
|
||||
export function getMockGobyFingerprints(params?: {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
filter?: string
|
||||
}): PaginatedResponse<GobyFingerprint> {
|
||||
const page = params?.page || 1
|
||||
const pageSize = params?.pageSize || 10
|
||||
const filter = params?.filter?.toLowerCase() || ''
|
||||
|
||||
let filtered = mockGobyFingerprints
|
||||
if (filter) {
|
||||
filtered = filtered.filter(f => f.name.toLowerCase().includes(filter))
|
||||
}
|
||||
|
||||
const total = filtered.length
|
||||
const totalPages = Math.ceil(total / pageSize)
|
||||
const start = (page - 1) * pageSize
|
||||
const results = filtered.slice(start, start + pageSize)
|
||||
|
||||
return { results, total, page, pageSize, totalPages }
|
||||
}
|
||||
|
||||
export function getMockWappalyzerFingerprints(params?: {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
filter?: string
|
||||
}): PaginatedResponse<WappalyzerFingerprint> {
|
||||
const page = params?.page || 1
|
||||
const pageSize = params?.pageSize || 10
|
||||
const filter = params?.filter?.toLowerCase() || ''
|
||||
|
||||
let filtered = mockWappalyzerFingerprints
|
||||
if (filter) {
|
||||
filtered = filtered.filter(f => f.name.toLowerCase().includes(filter))
|
||||
}
|
||||
|
||||
const total = filtered.length
|
||||
const totalPages = Math.ceil(total / pageSize)
|
||||
const start = (page - 1) * pageSize
|
||||
const results = filtered.slice(start, start + pageSize)
|
||||
|
||||
return { results, total, page, pageSize, totalPages }
|
||||
}
|
||||
|
||||
export function getMockFingersFingerprints(params?: {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
filter?: string
|
||||
}): PaginatedResponse<FingersFingerprint> {
|
||||
const page = params?.page || 1
|
||||
const pageSize = params?.pageSize || 10
|
||||
const filter = params?.filter?.toLowerCase() || ''
|
||||
|
||||
let filtered = mockFingersFingerprints
|
||||
if (filter) {
|
||||
filtered = filtered.filter(f => f.name.toLowerCase().includes(filter))
|
||||
}
|
||||
|
||||
const total = filtered.length
|
||||
const totalPages = Math.ceil(total / pageSize)
|
||||
const start = (page - 1) * pageSize
|
||||
const results = filtered.slice(start, start + pageSize)
|
||||
|
||||
return { results, total, page, pageSize, totalPages }
|
||||
}
|
||||
|
||||
export function getMockFingerPrintHubFingerprints(params?: {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
filter?: string
|
||||
}): PaginatedResponse<FingerPrintHubFingerprint> {
|
||||
const page = params?.page || 1
|
||||
const pageSize = params?.pageSize || 10
|
||||
const filter = params?.filter?.toLowerCase() || ''
|
||||
|
||||
let filtered = mockFingerPrintHubFingerprints
|
||||
if (filter) {
|
||||
filtered = filtered.filter(f => f.name.toLowerCase().includes(filter))
|
||||
}
|
||||
|
||||
const total = filtered.length
|
||||
const totalPages = Math.ceil(total / pageSize)
|
||||
const start = (page - 1) * pageSize
|
||||
const results = filtered.slice(start, start + pageSize)
|
||||
|
||||
return { results, total, page, pageSize, totalPages }
|
||||
}
|
||||
|
||||
export function getMockARLFingerprints(params?: {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
filter?: string
|
||||
}): PaginatedResponse<ARLFingerprint> {
|
||||
const page = params?.page || 1
|
||||
const pageSize = params?.pageSize || 10
|
||||
const filter = params?.filter?.toLowerCase() || ''
|
||||
|
||||
let filtered = mockARLFingerprints
|
||||
if (filter) {
|
||||
filtered = filtered.filter(f => f.name.toLowerCase().includes(filter))
|
||||
}
|
||||
|
||||
const total = filtered.length
|
||||
const totalPages = Math.ceil(total / pageSize)
|
||||
const start = (page - 1) * pageSize
|
||||
const results = filtered.slice(start, start + pageSize)
|
||||
|
||||
return { results, total, page, pageSize, totalPages }
|
||||
}
|
||||
|
||||
export function getMockFingerprintStats(): FingerprintStats {
|
||||
return mockFingerprintStats
|
||||
}
|
||||
118
frontend/mock/data/ip-addresses.ts
Normal file
118
frontend/mock/data/ip-addresses.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
import type { IPAddress, GetIPAddressesResponse } from '@/types/ip-address.types'
|
||||
|
||||
// 使用函数生成IP地址
|
||||
const ip = (a: number, b: number, c: number, d: number) => `${a}.${b}.${c}.${d}`
|
||||
|
||||
export const mockIPAddresses: IPAddress[] = [
|
||||
{
|
||||
ip: ip(192, 0, 2, 1),
|
||||
hosts: ['router.local', 'gateway.lan'],
|
||||
ports: [80, 443, 22, 53],
|
||||
createdAt: '2024-12-28T10:00:00Z',
|
||||
},
|
||||
{
|
||||
ip: ip(192, 0, 2, 10),
|
||||
hosts: ['api.acme.com', 'backend.acme.com'],
|
||||
ports: [80, 443, 8080, 3306],
|
||||
createdAt: '2024-12-28T10:01:00Z',
|
||||
},
|
||||
{
|
||||
ip: ip(192, 0, 2, 11),
|
||||
hosts: ['web.acme.com', 'www.acme.com'],
|
||||
ports: [80, 443],
|
||||
createdAt: '2024-12-28T10:02:00Z',
|
||||
},
|
||||
{
|
||||
ip: ip(198, 51, 100, 50),
|
||||
hosts: ['db.internal.acme.com'],
|
||||
ports: [3306, 5432, 27017],
|
||||
createdAt: '2024-12-28T10:03:00Z',
|
||||
},
|
||||
{
|
||||
ip: ip(203, 0, 113, 50),
|
||||
hosts: ['cdn.acme.com'],
|
||||
ports: [80, 443],
|
||||
createdAt: '2024-12-28T10:04:00Z',
|
||||
},
|
||||
{
|
||||
ip: ip(198, 51, 100, 10),
|
||||
hosts: ['mail.acme.com', 'smtp.acme.com'],
|
||||
ports: [25, 465, 587, 993, 995],
|
||||
createdAt: '2024-12-28T10:05:00Z',
|
||||
},
|
||||
{
|
||||
ip: ip(192, 0, 2, 100),
|
||||
hosts: ['jenkins.acme.com'],
|
||||
ports: [8080, 50000],
|
||||
createdAt: '2024-12-28T10:06:00Z',
|
||||
},
|
||||
{
|
||||
ip: ip(192, 0, 2, 101),
|
||||
hosts: ['gitlab.acme.com'],
|
||||
ports: [80, 443, 22],
|
||||
createdAt: '2024-12-28T10:07:00Z',
|
||||
},
|
||||
{
|
||||
ip: ip(192, 0, 2, 102),
|
||||
hosts: ['k8s.acme.com', 'kubernetes.acme.com'],
|
||||
ports: [6443, 10250, 10251, 10252],
|
||||
createdAt: '2024-12-28T10:08:00Z',
|
||||
},
|
||||
{
|
||||
ip: ip(192, 0, 2, 103),
|
||||
hosts: ['elastic.acme.com'],
|
||||
ports: [9200, 9300, 5601],
|
||||
createdAt: '2024-12-28T10:09:00Z',
|
||||
},
|
||||
{
|
||||
ip: ip(192, 0, 2, 104),
|
||||
hosts: ['redis.acme.com'],
|
||||
ports: [6379],
|
||||
createdAt: '2024-12-28T10:10:00Z',
|
||||
},
|
||||
{
|
||||
ip: ip(192, 0, 2, 105),
|
||||
hosts: ['mq.acme.com', 'rabbitmq.acme.com'],
|
||||
ports: [5672, 15672],
|
||||
createdAt: '2024-12-28T10:11:00Z',
|
||||
},
|
||||
]
|
||||
|
||||
export function getMockIPAddresses(params?: {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
filter?: string
|
||||
targetId?: number
|
||||
scanId?: number
|
||||
}): GetIPAddressesResponse {
|
||||
const page = params?.page || 1
|
||||
const pageSize = params?.pageSize || 10
|
||||
const filter = params?.filter?.toLowerCase() || ''
|
||||
|
||||
let filtered = mockIPAddresses
|
||||
|
||||
if (filter) {
|
||||
filtered = filtered.filter(
|
||||
ipAddr =>
|
||||
ipAddr.ip.toLowerCase().includes(filter) ||
|
||||
ipAddr.hosts.some(h => h.toLowerCase().includes(filter))
|
||||
)
|
||||
}
|
||||
|
||||
const total = filtered.length
|
||||
const totalPages = Math.ceil(total / pageSize)
|
||||
const start = (page - 1) * pageSize
|
||||
const results = filtered.slice(start, start + pageSize)
|
||||
|
||||
return {
|
||||
results,
|
||||
total,
|
||||
page,
|
||||
pageSize,
|
||||
totalPages,
|
||||
}
|
||||
}
|
||||
|
||||
export function getMockIPAddressByIP(ipStr: string): IPAddress | undefined {
|
||||
return mockIPAddresses.find(addr => addr.ip === ipStr)
|
||||
}
|
||||
35
frontend/mock/data/notification-settings.ts
Normal file
35
frontend/mock/data/notification-settings.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import type {
|
||||
NotificationSettings,
|
||||
GetNotificationSettingsResponse,
|
||||
UpdateNotificationSettingsResponse,
|
||||
} from '@/types/notification-settings.types'
|
||||
|
||||
export const mockNotificationSettings: NotificationSettings = {
|
||||
discord: {
|
||||
enabled: true,
|
||||
webhookUrl: 'https://discord.com/api/webhooks/1234567890/abcdefghijklmnop',
|
||||
},
|
||||
categories: {
|
||||
scan: true,
|
||||
vulnerability: true,
|
||||
asset: true,
|
||||
system: false,
|
||||
},
|
||||
}
|
||||
|
||||
export function getMockNotificationSettings(): GetNotificationSettingsResponse {
|
||||
return mockNotificationSettings
|
||||
}
|
||||
|
||||
export function updateMockNotificationSettings(
|
||||
settings: NotificationSettings
|
||||
): UpdateNotificationSettingsResponse {
|
||||
// 模拟更新设置
|
||||
Object.assign(mockNotificationSettings, settings)
|
||||
|
||||
return {
|
||||
message: 'Notification settings updated successfully',
|
||||
discord: mockNotificationSettings.discord,
|
||||
categories: mockNotificationSettings.categories,
|
||||
}
|
||||
}
|
||||
240
frontend/mock/data/nuclei-templates.ts
Normal file
240
frontend/mock/data/nuclei-templates.ts
Normal file
@@ -0,0 +1,240 @@
|
||||
import type {
|
||||
NucleiTemplateTreeNode,
|
||||
NucleiTemplateTreeResponse,
|
||||
NucleiTemplateContent,
|
||||
} from '@/types/nuclei.types'
|
||||
|
||||
export const mockNucleiTemplateTree: NucleiTemplateTreeNode[] = [
|
||||
{
|
||||
type: 'folder',
|
||||
name: 'cves',
|
||||
path: 'cves',
|
||||
children: [
|
||||
{
|
||||
type: 'folder',
|
||||
name: '2024',
|
||||
path: 'cves/2024',
|
||||
children: [
|
||||
{
|
||||
type: 'file',
|
||||
name: 'CVE-2024-1234.yaml',
|
||||
path: 'cves/2024/CVE-2024-1234.yaml',
|
||||
templateId: 'CVE-2024-1234',
|
||||
severity: 'critical',
|
||||
tags: ['cve', 'rce'],
|
||||
},
|
||||
{
|
||||
type: 'file',
|
||||
name: 'CVE-2024-5678.yaml',
|
||||
path: 'cves/2024/CVE-2024-5678.yaml',
|
||||
templateId: 'CVE-2024-5678',
|
||||
severity: 'high',
|
||||
tags: ['cve', 'sqli'],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'folder',
|
||||
name: '2023',
|
||||
path: 'cves/2023',
|
||||
children: [
|
||||
{
|
||||
type: 'file',
|
||||
name: 'CVE-2023-9876.yaml',
|
||||
path: 'cves/2023/CVE-2023-9876.yaml',
|
||||
templateId: 'CVE-2023-9876',
|
||||
severity: 'high',
|
||||
tags: ['cve', 'auth-bypass'],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'folder',
|
||||
name: 'vulnerabilities',
|
||||
path: 'vulnerabilities',
|
||||
children: [
|
||||
{
|
||||
type: 'folder',
|
||||
name: 'generic',
|
||||
path: 'vulnerabilities/generic',
|
||||
children: [
|
||||
{
|
||||
type: 'file',
|
||||
name: 'sqli-error-based.yaml',
|
||||
path: 'vulnerabilities/generic/sqli-error-based.yaml',
|
||||
templateId: 'sqli-error-based',
|
||||
severity: 'high',
|
||||
tags: ['sqli', 'generic'],
|
||||
},
|
||||
{
|
||||
type: 'file',
|
||||
name: 'xss-reflected.yaml',
|
||||
path: 'vulnerabilities/generic/xss-reflected.yaml',
|
||||
templateId: 'xss-reflected',
|
||||
severity: 'medium',
|
||||
tags: ['xss', 'generic'],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'folder',
|
||||
name: 'technologies',
|
||||
path: 'technologies',
|
||||
children: [
|
||||
{
|
||||
type: 'file',
|
||||
name: 'nginx-version.yaml',
|
||||
path: 'technologies/nginx-version.yaml',
|
||||
templateId: 'nginx-version',
|
||||
severity: 'info',
|
||||
tags: ['tech', 'nginx'],
|
||||
},
|
||||
{
|
||||
type: 'file',
|
||||
name: 'apache-detect.yaml',
|
||||
path: 'technologies/apache-detect.yaml',
|
||||
templateId: 'apache-detect',
|
||||
severity: 'info',
|
||||
tags: ['tech', 'apache'],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'folder',
|
||||
name: 'exposures',
|
||||
path: 'exposures',
|
||||
children: [
|
||||
{
|
||||
type: 'folder',
|
||||
name: 'configs',
|
||||
path: 'exposures/configs',
|
||||
children: [
|
||||
{
|
||||
type: 'file',
|
||||
name: 'git-config.yaml',
|
||||
path: 'exposures/configs/git-config.yaml',
|
||||
templateId: 'git-config',
|
||||
severity: 'medium',
|
||||
tags: ['exposure', 'git'],
|
||||
},
|
||||
{
|
||||
type: 'file',
|
||||
name: 'env-file.yaml',
|
||||
path: 'exposures/configs/env-file.yaml',
|
||||
templateId: 'env-file',
|
||||
severity: 'high',
|
||||
tags: ['exposure', 'env'],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
export const mockNucleiTemplateContent: Record<string, NucleiTemplateContent> = {
|
||||
'cves/2024/CVE-2024-1234.yaml': {
|
||||
path: 'cves/2024/CVE-2024-1234.yaml',
|
||||
name: 'CVE-2024-1234.yaml',
|
||||
templateId: 'CVE-2024-1234',
|
||||
severity: 'critical',
|
||||
tags: ['cve', 'rce'],
|
||||
content: `id: CVE-2024-1234
|
||||
|
||||
info:
|
||||
name: Example RCE Vulnerability
|
||||
author: pdteam
|
||||
severity: critical
|
||||
description: |
|
||||
Example remote code execution vulnerability.
|
||||
reference:
|
||||
- https://example.com/cve-2024-1234
|
||||
tags: cve,cve2024,rce
|
||||
|
||||
http:
|
||||
- method: POST
|
||||
path:
|
||||
- "{{BaseURL}}/api/execute"
|
||||
headers:
|
||||
Content-Type: application/json
|
||||
body: '{"cmd": "id"}'
|
||||
matchers:
|
||||
- type: word
|
||||
words:
|
||||
- "uid="
|
||||
- "gid="
|
||||
condition: and
|
||||
`,
|
||||
},
|
||||
'vulnerabilities/generic/sqli-error-based.yaml': {
|
||||
path: 'vulnerabilities/generic/sqli-error-based.yaml',
|
||||
name: 'sqli-error-based.yaml',
|
||||
templateId: 'sqli-error-based',
|
||||
severity: 'high',
|
||||
tags: ['sqli', 'generic'],
|
||||
content: `id: sqli-error-based
|
||||
|
||||
info:
|
||||
name: Error Based SQL Injection
|
||||
author: pdteam
|
||||
severity: high
|
||||
tags: sqli,generic
|
||||
|
||||
http:
|
||||
- method: GET
|
||||
path:
|
||||
- "{{BaseURL}}/?id=1'"
|
||||
matchers:
|
||||
- type: word
|
||||
words:
|
||||
- "SQL syntax"
|
||||
- "mysql_fetch"
|
||||
- "You have an error"
|
||||
condition: or
|
||||
`,
|
||||
},
|
||||
'technologies/nginx-version.yaml': {
|
||||
path: 'technologies/nginx-version.yaml',
|
||||
name: 'nginx-version.yaml',
|
||||
templateId: 'nginx-version',
|
||||
severity: 'info',
|
||||
tags: ['tech', 'nginx'],
|
||||
content: `id: nginx-version
|
||||
|
||||
info:
|
||||
name: Nginx Version Detection
|
||||
author: pdteam
|
||||
severity: info
|
||||
tags: tech,nginx
|
||||
|
||||
http:
|
||||
- method: GET
|
||||
path:
|
||||
- "{{BaseURL}}/"
|
||||
matchers:
|
||||
- type: regex
|
||||
part: header
|
||||
regex:
|
||||
- "nginx/([\\d.]+)"
|
||||
extractors:
|
||||
- type: regex
|
||||
part: header
|
||||
group: 1
|
||||
regex:
|
||||
- "nginx/([\\d.]+)"
|
||||
`,
|
||||
},
|
||||
}
|
||||
|
||||
export function getMockNucleiTemplateTree(): NucleiTemplateTreeResponse {
|
||||
return {
|
||||
roots: mockNucleiTemplateTree,
|
||||
}
|
||||
}
|
||||
|
||||
export function getMockNucleiTemplateContent(path: string): NucleiTemplateContent | undefined {
|
||||
return mockNucleiTemplateContent[path]
|
||||
}
|
||||
154
frontend/mock/data/search.ts
Normal file
154
frontend/mock/data/search.ts
Normal file
@@ -0,0 +1,154 @@
|
||||
import type {
|
||||
SearchResponse,
|
||||
WebsiteSearchResult,
|
||||
EndpointSearchResult,
|
||||
AssetType,
|
||||
} from '@/types/search.types'
|
||||
import { mockWebsites } from './websites'
|
||||
import { mockEndpoints } from './endpoints'
|
||||
|
||||
// 将 Website 转换为搜索结果格式
|
||||
function websiteToSearchResult(website: typeof mockWebsites[0]): WebsiteSearchResult {
|
||||
return {
|
||||
id: website.id,
|
||||
url: website.url,
|
||||
host: website.host,
|
||||
title: website.title,
|
||||
technologies: website.tech || [],
|
||||
statusCode: website.statusCode,
|
||||
contentLength: website.contentLength,
|
||||
contentType: website.contentType,
|
||||
webserver: website.webserver,
|
||||
location: website.location,
|
||||
vhost: website.vhost,
|
||||
responseHeaders: {},
|
||||
responseBody: website.responseBody || '',
|
||||
createdAt: website.createdAt,
|
||||
targetId: website.target ?? 1,
|
||||
vulnerabilities: [],
|
||||
}
|
||||
}
|
||||
|
||||
// 将 Endpoint 转换为搜索结果格式
|
||||
function endpointToSearchResult(endpoint: typeof mockEndpoints[0]): EndpointSearchResult {
|
||||
return {
|
||||
id: endpoint.id,
|
||||
url: endpoint.url,
|
||||
host: endpoint.host || '',
|
||||
title: endpoint.title,
|
||||
technologies: endpoint.tech || [],
|
||||
statusCode: endpoint.statusCode,
|
||||
contentLength: endpoint.contentLength,
|
||||
contentType: endpoint.contentType || '',
|
||||
webserver: endpoint.webserver || '',
|
||||
location: endpoint.location || '',
|
||||
vhost: null,
|
||||
responseHeaders: {},
|
||||
responseBody: '',
|
||||
createdAt: endpoint.createdAt ?? null,
|
||||
targetId: 1,
|
||||
matchedGfPatterns: endpoint.gfPatterns || [],
|
||||
}
|
||||
}
|
||||
|
||||
// 解析搜索表达式
|
||||
function parseSearchQuery(query: string): { field: string; operator: string; value: string }[] {
|
||||
const conditions: { field: string; operator: string; value: string }[] = []
|
||||
|
||||
// 简单解析:field="value" 或 field=="value" 或 field!="value"
|
||||
const regex = /(\w+)(==|!=|=)"([^"]+)"/g
|
||||
let match
|
||||
while ((match = regex.exec(query)) !== null) {
|
||||
conditions.push({
|
||||
field: match[1],
|
||||
operator: match[2],
|
||||
value: match[3],
|
||||
})
|
||||
}
|
||||
|
||||
return conditions
|
||||
}
|
||||
|
||||
// 检查记录是否匹配条件
|
||||
function matchesConditions(
|
||||
record: WebsiteSearchResult | EndpointSearchResult,
|
||||
conditions: { field: string; operator: string; value: string }[]
|
||||
): boolean {
|
||||
if (conditions.length === 0) return true
|
||||
|
||||
return conditions.every(cond => {
|
||||
let fieldValue: string | number | null = null
|
||||
|
||||
switch (cond.field) {
|
||||
case 'host':
|
||||
fieldValue = record.host
|
||||
break
|
||||
case 'url':
|
||||
fieldValue = record.url
|
||||
break
|
||||
case 'title':
|
||||
fieldValue = record.title
|
||||
break
|
||||
case 'tech':
|
||||
fieldValue = record.technologies.join(',')
|
||||
break
|
||||
case 'status':
|
||||
fieldValue = String(record.statusCode)
|
||||
break
|
||||
default:
|
||||
return true
|
||||
}
|
||||
|
||||
if (fieldValue === null) return false
|
||||
const strValue = String(fieldValue).toLowerCase()
|
||||
const searchValue = cond.value.toLowerCase()
|
||||
|
||||
switch (cond.operator) {
|
||||
case '=':
|
||||
return strValue.includes(searchValue)
|
||||
case '==':
|
||||
return strValue === searchValue
|
||||
case '!=':
|
||||
return !strValue.includes(searchValue)
|
||||
default:
|
||||
return true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function getMockSearchResults(params: {
|
||||
q?: string
|
||||
asset_type?: AssetType
|
||||
page?: number
|
||||
pageSize?: number
|
||||
}): SearchResponse {
|
||||
const { q = '', asset_type = 'website', page = 1, pageSize = 10 } = params
|
||||
|
||||
const conditions = parseSearchQuery(q)
|
||||
|
||||
let results: (WebsiteSearchResult | EndpointSearchResult)[]
|
||||
|
||||
if (asset_type === 'website') {
|
||||
results = mockWebsites
|
||||
.map(websiteToSearchResult)
|
||||
.filter(r => matchesConditions(r, conditions))
|
||||
} else {
|
||||
results = mockEndpoints
|
||||
.map(endpointToSearchResult)
|
||||
.filter(r => matchesConditions(r, conditions))
|
||||
}
|
||||
|
||||
const total = results.length
|
||||
const totalPages = Math.ceil(total / pageSize)
|
||||
const start = (page - 1) * pageSize
|
||||
const paginatedResults = results.slice(start, start + pageSize)
|
||||
|
||||
return {
|
||||
results: paginatedResults,
|
||||
total,
|
||||
page,
|
||||
pageSize,
|
||||
totalPages,
|
||||
assetType: asset_type,
|
||||
}
|
||||
}
|
||||
100
frontend/mock/data/system-logs.ts
Normal file
100
frontend/mock/data/system-logs.ts
Normal file
@@ -0,0 +1,100 @@
|
||||
import type { SystemLogResponse, LogFilesResponse, LogFile } from '@/types/system-log.types'
|
||||
|
||||
export const mockLogFiles: LogFile[] = [
|
||||
{
|
||||
filename: 'xingrin.log',
|
||||
category: 'system',
|
||||
size: 1234567,
|
||||
modifiedAt: '2024-12-28T10:00:00Z',
|
||||
},
|
||||
{
|
||||
filename: 'xingrin-error.log',
|
||||
category: 'error',
|
||||
size: 45678,
|
||||
modifiedAt: '2024-12-28T09:30:00Z',
|
||||
},
|
||||
{
|
||||
filename: 'worker.log',
|
||||
category: 'system',
|
||||
size: 234567,
|
||||
modifiedAt: '2024-12-28T10:00:00Z',
|
||||
},
|
||||
{
|
||||
filename: 'celery.log',
|
||||
category: 'system',
|
||||
size: 567890,
|
||||
modifiedAt: '2024-12-28T09:45:00Z',
|
||||
},
|
||||
{
|
||||
filename: 'nginx-access.log',
|
||||
category: 'system',
|
||||
size: 12345678,
|
||||
modifiedAt: '2024-12-28T10:00:00Z',
|
||||
},
|
||||
{
|
||||
filename: 'nginx-error.log',
|
||||
category: 'error',
|
||||
size: 23456,
|
||||
modifiedAt: '2024-12-28T08:00:00Z',
|
||||
},
|
||||
]
|
||||
|
||||
export const mockSystemLogContent = `[2024-12-28 10:00:00] INFO: Server started on port 8000
|
||||
[2024-12-28 10:00:01] INFO: Database connection established
|
||||
[2024-12-28 10:00:02] INFO: Redis connection established
|
||||
[2024-12-28 10:00:03] INFO: Worker node registered: local-worker-1
|
||||
[2024-12-28 10:00:05] INFO: Celery worker started with 4 concurrent tasks
|
||||
[2024-12-28 10:01:00] INFO: New scan task created: scan-001
|
||||
[2024-12-28 10:01:01] INFO: Task scan-001 assigned to worker local-worker-1
|
||||
[2024-12-28 10:01:05] INFO: Subdomain enumeration started for target: acme.com
|
||||
[2024-12-28 10:02:30] INFO: Found 45 subdomains for acme.com
|
||||
[2024-12-28 10:02:31] INFO: Port scanning started for 45 hosts
|
||||
[2024-12-28 10:05:00] INFO: Port scanning completed, found 123 open ports
|
||||
[2024-12-28 10:05:01] INFO: HTTP probing started for 123 endpoints
|
||||
[2024-12-28 10:08:00] INFO: HTTP probing completed, found 89 live websites
|
||||
[2024-12-28 10:08:01] INFO: Fingerprint detection started
|
||||
[2024-12-28 10:10:00] INFO: Fingerprint detection completed
|
||||
[2024-12-28 10:10:01] INFO: Vulnerability scanning started with nuclei
|
||||
[2024-12-28 10:15:00] INFO: Vulnerability scanning completed, found 5 vulnerabilities
|
||||
[2024-12-28 10:15:01] INFO: Scan task scan-001 completed successfully
|
||||
[2024-12-28 10:15:02] INFO: Results saved to database
|
||||
[2024-12-28 10:15:03] INFO: Notification sent to Discord webhook`
|
||||
|
||||
export const mockErrorLogContent = `[2024-12-28 08:30:00] ERROR: Connection refused: Redis server not responding
|
||||
[2024-12-28 08:30:01] ERROR: Retrying Redis connection in 5 seconds...
|
||||
[2024-12-28 08:30:06] INFO: Redis connection recovered
|
||||
[2024-12-28 09:15:00] WARNING: High memory usage detected (85%)
|
||||
[2024-12-28 09:15:01] INFO: Running garbage collection
|
||||
[2024-12-28 09:15:05] INFO: Memory usage reduced to 62%
|
||||
[2024-12-28 09:30:00] ERROR: Worker node disconnected: remote-worker-2
|
||||
[2024-12-28 09:30:01] WARNING: Reassigning 3 tasks from remote-worker-2
|
||||
[2024-12-28 09:30:05] INFO: Tasks reassigned successfully`
|
||||
|
||||
export function getMockLogFiles(): LogFilesResponse {
|
||||
return {
|
||||
files: mockLogFiles,
|
||||
}
|
||||
}
|
||||
|
||||
export function getMockSystemLogs(params?: {
|
||||
file?: string
|
||||
lines?: number
|
||||
}): SystemLogResponse {
|
||||
const filename = params?.file || 'xingrin.log'
|
||||
const lines = params?.lines || 100
|
||||
|
||||
let content: string
|
||||
if (filename.includes('error')) {
|
||||
content = mockErrorLogContent
|
||||
} else {
|
||||
content = mockSystemLogContent
|
||||
}
|
||||
|
||||
// 模拟行数限制
|
||||
const contentLines = content.split('\n')
|
||||
const limitedContent = contentLines.slice(-lines).join('\n')
|
||||
|
||||
return {
|
||||
content: limitedContent,
|
||||
}
|
||||
}
|
||||
149
frontend/mock/data/tools.ts
Normal file
149
frontend/mock/data/tools.ts
Normal file
@@ -0,0 +1,149 @@
|
||||
import type { Tool, GetToolsResponse } from '@/types/tool.types'
|
||||
|
||||
export const mockTools: Tool[] = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'subfinder',
|
||||
type: 'opensource',
|
||||
repoUrl: 'https://github.com/projectdiscovery/subfinder',
|
||||
version: 'v2.6.3',
|
||||
description: 'Fast passive subdomain enumeration tool.',
|
||||
categoryNames: ['subdomain', 'recon'],
|
||||
directory: '/opt/tools/subfinder',
|
||||
installCommand: 'go install -v github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest',
|
||||
updateCommand: 'go install -v github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest',
|
||||
versionCommand: 'subfinder -version',
|
||||
createdAt: '2024-12-20T10:00:00Z',
|
||||
updatedAt: '2024-12-28T10:00:00Z',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'httpx',
|
||||
type: 'opensource',
|
||||
repoUrl: 'https://github.com/projectdiscovery/httpx',
|
||||
version: 'v1.6.0',
|
||||
description: 'Fast and multi-purpose HTTP toolkit.',
|
||||
categoryNames: ['http', 'recon'],
|
||||
directory: '/opt/tools/httpx',
|
||||
installCommand: 'go install -v github.com/projectdiscovery/httpx/cmd/httpx@latest',
|
||||
updateCommand: 'go install -v github.com/projectdiscovery/httpx/cmd/httpx@latest',
|
||||
versionCommand: 'httpx -version',
|
||||
createdAt: '2024-12-20T10:01:00Z',
|
||||
updatedAt: '2024-12-28T10:01:00Z',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'nuclei',
|
||||
type: 'opensource',
|
||||
repoUrl: 'https://github.com/projectdiscovery/nuclei',
|
||||
version: 'v3.1.0',
|
||||
description: 'Fast and customizable vulnerability scanner.',
|
||||
categoryNames: ['vulnerability'],
|
||||
directory: '/opt/tools/nuclei',
|
||||
installCommand: 'go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest',
|
||||
updateCommand: 'go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest',
|
||||
versionCommand: 'nuclei -version',
|
||||
createdAt: '2024-12-20T10:02:00Z',
|
||||
updatedAt: '2024-12-28T10:02:00Z',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'naabu',
|
||||
type: 'opensource',
|
||||
repoUrl: 'https://github.com/projectdiscovery/naabu',
|
||||
version: 'v2.2.1',
|
||||
description: 'Fast port scanner written in go.',
|
||||
categoryNames: ['port', 'network'],
|
||||
directory: '/opt/tools/naabu',
|
||||
installCommand: 'go install -v github.com/projectdiscovery/naabu/v2/cmd/naabu@latest',
|
||||
updateCommand: 'go install -v github.com/projectdiscovery/naabu/v2/cmd/naabu@latest',
|
||||
versionCommand: 'naabu -version',
|
||||
createdAt: '2024-12-20T10:03:00Z',
|
||||
updatedAt: '2024-12-28T10:03:00Z',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'katana',
|
||||
type: 'opensource',
|
||||
repoUrl: 'https://github.com/projectdiscovery/katana',
|
||||
version: 'v1.0.4',
|
||||
description: 'Next-generation crawling and spidering framework.',
|
||||
categoryNames: ['crawler', 'recon'],
|
||||
directory: '/opt/tools/katana',
|
||||
installCommand: 'go install github.com/projectdiscovery/katana/cmd/katana@latest',
|
||||
updateCommand: 'go install github.com/projectdiscovery/katana/cmd/katana@latest',
|
||||
versionCommand: 'katana -version',
|
||||
createdAt: '2024-12-20T10:04:00Z',
|
||||
updatedAt: '2024-12-28T10:04:00Z',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: 'ffuf',
|
||||
type: 'opensource',
|
||||
repoUrl: 'https://github.com/ffuf/ffuf',
|
||||
version: 'v2.1.0',
|
||||
description: 'Fast web fuzzer written in Go.',
|
||||
categoryNames: ['directory', 'fuzzer'],
|
||||
directory: '/opt/tools/ffuf',
|
||||
installCommand: 'go install github.com/ffuf/ffuf/v2@latest',
|
||||
updateCommand: 'go install github.com/ffuf/ffuf/v2@latest',
|
||||
versionCommand: 'ffuf -V',
|
||||
createdAt: '2024-12-20T10:05:00Z',
|
||||
updatedAt: '2024-12-28T10:05:00Z',
|
||||
},
|
||||
{
|
||||
id: 7,
|
||||
name: 'amass',
|
||||
type: 'opensource',
|
||||
repoUrl: 'https://github.com/owasp-amass/amass',
|
||||
version: 'v4.2.0',
|
||||
description: 'In-depth attack surface mapping and asset discovery.',
|
||||
categoryNames: ['subdomain', 'recon'],
|
||||
directory: '/opt/tools/amass',
|
||||
installCommand: 'go install -v github.com/owasp-amass/amass/v4/...@master',
|
||||
updateCommand: 'go install -v github.com/owasp-amass/amass/v4/...@master',
|
||||
versionCommand: 'amass -version',
|
||||
createdAt: '2024-12-20T10:06:00Z',
|
||||
updatedAt: '2024-12-28T10:06:00Z',
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
name: 'xingfinger',
|
||||
type: 'custom',
|
||||
repoUrl: '',
|
||||
version: '1.0.0',
|
||||
description: '自定义指纹识别工具',
|
||||
categoryNames: ['recon'],
|
||||
directory: '/opt/tools/xingfinger',
|
||||
installCommand: '',
|
||||
updateCommand: '',
|
||||
versionCommand: '',
|
||||
createdAt: '2024-12-20T10:07:00Z',
|
||||
updatedAt: '2024-12-28T10:07:00Z',
|
||||
},
|
||||
]
|
||||
|
||||
export function getMockTools(params?: {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
}): GetToolsResponse {
|
||||
const page = params?.page || 1
|
||||
const pageSize = params?.pageSize || 10
|
||||
|
||||
const total = mockTools.length
|
||||
const totalPages = Math.ceil(total / pageSize)
|
||||
const start = (page - 1) * pageSize
|
||||
const tools = mockTools.slice(start, start + pageSize)
|
||||
|
||||
return {
|
||||
tools,
|
||||
total,
|
||||
page,
|
||||
pageSize,
|
||||
totalPages,
|
||||
}
|
||||
}
|
||||
|
||||
export function getMockToolById(id: number): Tool | undefined {
|
||||
return mockTools.find(t => t.id === id)
|
||||
}
|
||||
119
frontend/mock/data/wordlists.ts
Normal file
119
frontend/mock/data/wordlists.ts
Normal file
@@ -0,0 +1,119 @@
|
||||
import type { Wordlist, GetWordlistsResponse } from '@/types/wordlist.types'
|
||||
|
||||
export const mockWordlists: Wordlist[] = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'common-dirs.txt',
|
||||
description: '常用目录字典',
|
||||
fileSize: 45678,
|
||||
lineCount: 4567,
|
||||
fileHash: 'a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6',
|
||||
createdAt: '2024-12-20T10:00:00Z',
|
||||
updatedAt: '2024-12-28T10:00:00Z',
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
name: 'subdomains-top1million.txt',
|
||||
description: 'Top 100万子域名字典',
|
||||
fileSize: 12345678,
|
||||
lineCount: 1000000,
|
||||
fileHash: 'b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7',
|
||||
createdAt: '2024-12-20T10:01:00Z',
|
||||
updatedAt: '2024-12-28T10:01:00Z',
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: 'api-endpoints.txt',
|
||||
description: 'API 端点字典',
|
||||
fileSize: 23456,
|
||||
lineCount: 2345,
|
||||
fileHash: 'c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8',
|
||||
createdAt: '2024-12-20T10:02:00Z',
|
||||
updatedAt: '2024-12-28T10:02:00Z',
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
name: 'params.txt',
|
||||
description: '常用参数名字典',
|
||||
fileSize: 8901,
|
||||
lineCount: 890,
|
||||
fileHash: 'd4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9',
|
||||
createdAt: '2024-12-20T10:03:00Z',
|
||||
updatedAt: '2024-12-28T10:03:00Z',
|
||||
},
|
||||
{
|
||||
id: 5,
|
||||
name: 'sensitive-files.txt',
|
||||
description: '敏感文件字典',
|
||||
fileSize: 5678,
|
||||
lineCount: 567,
|
||||
fileHash: 'e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0',
|
||||
createdAt: '2024-12-20T10:04:00Z',
|
||||
updatedAt: '2024-12-28T10:04:00Z',
|
||||
},
|
||||
{
|
||||
id: 6,
|
||||
name: 'raft-large-directories.txt',
|
||||
description: 'RAFT 大型目录字典',
|
||||
fileSize: 987654,
|
||||
lineCount: 98765,
|
||||
fileHash: 'f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1',
|
||||
createdAt: '2024-12-20T10:05:00Z',
|
||||
updatedAt: '2024-12-28T10:05:00Z',
|
||||
},
|
||||
]
|
||||
|
||||
export const mockWordlistContent = `admin
|
||||
api
|
||||
backup
|
||||
config
|
||||
dashboard
|
||||
debug
|
||||
dev
|
||||
docs
|
||||
download
|
||||
files
|
||||
images
|
||||
js
|
||||
login
|
||||
logs
|
||||
manager
|
||||
private
|
||||
public
|
||||
static
|
||||
test
|
||||
upload
|
||||
users
|
||||
v1
|
||||
v2
|
||||
wp-admin
|
||||
wp-content`
|
||||
|
||||
export function getMockWordlists(params?: {
|
||||
page?: number
|
||||
pageSize?: number
|
||||
}): GetWordlistsResponse {
|
||||
const page = params?.page || 1
|
||||
const pageSize = params?.pageSize || 10
|
||||
|
||||
const total = mockWordlists.length
|
||||
const totalPages = Math.ceil(total / pageSize)
|
||||
const start = (page - 1) * pageSize
|
||||
const results = mockWordlists.slice(start, start + pageSize)
|
||||
|
||||
return {
|
||||
results,
|
||||
total,
|
||||
page,
|
||||
pageSize,
|
||||
totalPages,
|
||||
}
|
||||
}
|
||||
|
||||
export function getMockWordlistById(id: number): Wordlist | undefined {
|
||||
return mockWordlists.find(w => w.id === id)
|
||||
}
|
||||
|
||||
export function getMockWordlistContent(): string {
|
||||
return mockWordlistContent
|
||||
}
|
||||
@@ -105,3 +105,80 @@ export {
|
||||
getMockScheduledScans,
|
||||
getMockScheduledScanById,
|
||||
} from './data/scheduled-scans'
|
||||
|
||||
// Directories
|
||||
export {
|
||||
mockDirectories,
|
||||
getMockDirectories,
|
||||
getMockDirectoryById,
|
||||
} from './data/directories'
|
||||
|
||||
// Fingerprints
|
||||
export {
|
||||
mockEholeFingerprints,
|
||||
mockGobyFingerprints,
|
||||
mockWappalyzerFingerprints,
|
||||
mockFingersFingerprints,
|
||||
mockFingerPrintHubFingerprints,
|
||||
mockARLFingerprints,
|
||||
mockFingerprintStats,
|
||||
getMockEholeFingerprints,
|
||||
getMockGobyFingerprints,
|
||||
getMockWappalyzerFingerprints,
|
||||
getMockFingersFingerprints,
|
||||
getMockFingerPrintHubFingerprints,
|
||||
getMockARLFingerprints,
|
||||
getMockFingerprintStats,
|
||||
} from './data/fingerprints'
|
||||
|
||||
// IP Addresses
|
||||
export {
|
||||
mockIPAddresses,
|
||||
getMockIPAddresses,
|
||||
getMockIPAddressByIP,
|
||||
} from './data/ip-addresses'
|
||||
|
||||
// Search
|
||||
export {
|
||||
getMockSearchResults,
|
||||
} from './data/search'
|
||||
|
||||
// Tools
|
||||
export {
|
||||
mockTools,
|
||||
getMockTools,
|
||||
getMockToolById,
|
||||
} from './data/tools'
|
||||
|
||||
// Wordlists
|
||||
export {
|
||||
mockWordlists,
|
||||
mockWordlistContent,
|
||||
getMockWordlists,
|
||||
getMockWordlistById,
|
||||
getMockWordlistContent,
|
||||
} from './data/wordlists'
|
||||
|
||||
// Nuclei Templates
|
||||
export {
|
||||
mockNucleiTemplateTree,
|
||||
mockNucleiTemplateContent,
|
||||
getMockNucleiTemplateTree,
|
||||
getMockNucleiTemplateContent,
|
||||
} from './data/nuclei-templates'
|
||||
|
||||
// System Logs
|
||||
export {
|
||||
mockLogFiles,
|
||||
mockSystemLogContent,
|
||||
mockErrorLogContent,
|
||||
getMockLogFiles,
|
||||
getMockSystemLogs,
|
||||
} from './data/system-logs'
|
||||
|
||||
// Notification Settings
|
||||
export {
|
||||
mockNotificationSettings,
|
||||
getMockNotificationSettings,
|
||||
updateMockNotificationSettings,
|
||||
} from './data/notification-settings'
|
||||
|
||||
Reference in New Issue
Block a user