Skip to content

Commit 3c5f299

Browse files
committed
feat: 添加会话Body字段动态替换功能及UI优化
- 新增会话Body字段管理功能,支持动态替换请求体字段 - 统一Header规则管理、会话Header管理、会话Body字段标签页的工具栏样式(高度38px) - 为所有配置标签页和任务列表添加空数据提示,优化空状态展示 - 修复API路由前缀问题 - 调整下拉框宽度以完整显示选项内容
1 parent 1d438cc commit 3c5f299

21 files changed

Lines changed: 5905 additions & 49 deletions

.qoder/quests/session-field-dynamic-replacement.md

Lines changed: 1721 additions & 0 deletions
Large diffs are not rendered by default.

package.json

Lines changed: 0 additions & 1 deletion
This file was deleted.

pnpm-lock.yaml

Lines changed: 0 additions & 9 deletions
This file was deleted.
Lines changed: 306 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,306 @@
1+
"""
2+
Body Field Controller - 会话Body字段管理API
3+
4+
提供会话Body字段的CRUD接口和预览功能。
5+
"""
6+
7+
from fastapi import APIRouter, Request, status
8+
from typing import List
9+
10+
from model.BaseResponseMsg import BaseResponseMsg
11+
from model.SessionBodyField import (
12+
SessionBodyFieldBatchCreate,
13+
SessionBodyFieldUpdate,
14+
SessionBodyFieldListResponse,
15+
SessionBodyFieldResponse
16+
)
17+
from model.DataStore import DataStore
18+
19+
import logging
20+
logger = logging.getLogger(__name__)
21+
22+
router = APIRouter()
23+
24+
25+
@router.post('/session-body-fields')
26+
async def set_session_body_fields(
27+
batch_create: SessionBodyFieldBatchCreate,
28+
request: Request
29+
) -> BaseResponseMsg:
30+
"""批量设置会话Body字段"""
31+
try:
32+
client_ip = request.client.host
33+
manager = DataStore.get_session_body_field_manager()
34+
35+
if manager is None:
36+
return BaseResponseMsg(
37+
data=None,
38+
msg="Body字段管理器不可用",
39+
success=False,
40+
code=status.HTTP_500_INTERNAL_SERVER_ERROR
41+
)
42+
43+
count = manager.set_session_body_fields_batch(
44+
client_ip,
45+
batch_create.fields
46+
)
47+
48+
logger.info(f"Set {count} session body fields for {client_ip}")
49+
50+
return BaseResponseMsg(
51+
data={"count": count, "client_ip": client_ip},
52+
msg=f"成功设置{count}个会话Body字段",
53+
success=True,
54+
code=status.HTTP_200_OK
55+
)
56+
except Exception as e:
57+
logger.error(f"Failed to set session body fields: {e}")
58+
return BaseResponseMsg(
59+
data=None,
60+
msg=str(e),
61+
success=False,
62+
code=status.HTTP_500_INTERNAL_SERVER_ERROR
63+
)
64+
65+
66+
@router.get('/session-body-fields')
67+
async def get_session_body_fields(request: Request) -> BaseResponseMsg:
68+
"""获取会话Body字段列表"""
69+
try:
70+
client_ip = request.client.host
71+
manager = DataStore.get_session_body_field_manager()
72+
73+
if manager is None:
74+
return BaseResponseMsg(
75+
data=None,
76+
msg="Body字段管理器不可用",
77+
success=False,
78+
code=status.HTTP_500_INTERNAL_SERVER_ERROR
79+
)
80+
81+
# 获取所有字段(包括过期的)
82+
all_fields = manager.get_all_session_body_fields(client_ip)
83+
84+
# 转换为响应格式
85+
field_responses = []
86+
for field in all_fields:
87+
field_dict = field.to_dict()
88+
field_responses.append(SessionBodyFieldResponse(**field_dict))
89+
90+
response_data = SessionBodyFieldListResponse(
91+
client_ip=client_ip,
92+
fields=field_responses,
93+
total_count=len(field_responses)
94+
)
95+
96+
return BaseResponseMsg(
97+
data=response_data.dict(),
98+
msg="获取会话Body字段成功",
99+
success=True,
100+
code=status.HTTP_200_OK
101+
)
102+
except Exception as e:
103+
logger.error(f"Failed to get session body fields: {e}")
104+
return BaseResponseMsg(
105+
data=None,
106+
msg=str(e),
107+
success=False,
108+
code=status.HTTP_500_INTERNAL_SERVER_ERROR
109+
)
110+
111+
112+
@router.put('/session-body-fields/{field_name}')
113+
async def update_session_body_field(
114+
field_name: str,
115+
field_update: SessionBodyFieldUpdate,
116+
request: Request
117+
) -> BaseResponseMsg:
118+
"""更新单个会话Body字段"""
119+
try:
120+
client_ip = request.client.host
121+
manager = DataStore.get_session_body_field_manager()
122+
123+
if manager is None:
124+
return BaseResponseMsg(
125+
data=None,
126+
msg="Body字段管理器不可用",
127+
success=False,
128+
code=status.HTTP_500_INTERNAL_SERVER_ERROR
129+
)
130+
131+
success = manager.update_session_body_field(client_ip, field_name, field_update)
132+
133+
if success:
134+
return BaseResponseMsg(
135+
data={"client_ip": client_ip, "field_name": field_name},
136+
msg="会话Body字段更新成功",
137+
success=True,
138+
code=status.HTTP_200_OK
139+
)
140+
else:
141+
return BaseResponseMsg(
142+
data=None,
143+
msg="会话Body字段更新失败",
144+
success=False,
145+
code=status.HTTP_404_NOT_FOUND
146+
)
147+
except Exception as e:
148+
logger.error(f"Failed to update session body field: {e}")
149+
return BaseResponseMsg(
150+
data=None,
151+
msg=str(e),
152+
success=False,
153+
code=status.HTTP_500_INTERNAL_SERVER_ERROR
154+
)
155+
156+
157+
@router.delete('/session-body-fields/{field_name}')
158+
async def delete_session_body_field(
159+
field_name: str,
160+
request: Request
161+
) -> BaseResponseMsg:
162+
"""删除单个会话Body字段"""
163+
try:
164+
client_ip = request.client.host
165+
manager = DataStore.get_session_body_field_manager()
166+
167+
if manager is None:
168+
return BaseResponseMsg(
169+
data=None,
170+
msg="Body字段管理器不可用",
171+
success=False,
172+
code=status.HTTP_500_INTERNAL_SERVER_ERROR
173+
)
174+
175+
removed = manager.remove_session_body_field(client_ip, field_name)
176+
177+
if removed:
178+
return BaseResponseMsg(
179+
data={"client_ip": client_ip, "field_name": field_name},
180+
msg="会话Body字段删除成功",
181+
success=True,
182+
code=status.HTTP_200_OK
183+
)
184+
else:
185+
return BaseResponseMsg(
186+
data=None,
187+
msg="没有找到指定的会话Body字段",
188+
success=False,
189+
code=status.HTTP_404_NOT_FOUND
190+
)
191+
except Exception as e:
192+
logger.error(f"Failed to delete session body field: {e}")
193+
return BaseResponseMsg(
194+
data=None,
195+
msg=str(e),
196+
success=False,
197+
code=status.HTTP_500_INTERNAL_SERVER_ERROR
198+
)
199+
200+
201+
@router.delete('/session-body-fields')
202+
async def clear_session_body_fields(request: Request) -> BaseResponseMsg:
203+
"""清除所有会话Body字段"""
204+
try:
205+
client_ip = request.client.host
206+
manager = DataStore.get_session_body_field_manager()
207+
208+
if manager is None:
209+
return BaseResponseMsg(
210+
data=None,
211+
msg="Body字段管理器不可用",
212+
success=False,
213+
code=status.HTTP_500_INTERNAL_SERVER_ERROR
214+
)
215+
216+
cleared = manager.clear_session_body_fields(client_ip)
217+
218+
if cleared:
219+
return BaseResponseMsg(
220+
data={"client_ip": client_ip},
221+
msg="会话Body字段清除成功",
222+
success=True,
223+
code=status.HTTP_200_OK
224+
)
225+
else:
226+
return BaseResponseMsg(
227+
data={"client_ip": client_ip},
228+
msg="没有找到需要清除的会话Body字段",
229+
success=True,
230+
code=status.HTTP_200_OK
231+
)
232+
except Exception as e:
233+
logger.error(f"Failed to clear session body fields: {e}")
234+
return BaseResponseMsg(
235+
data=None,
236+
msg=str(e),
237+
success=False,
238+
code=status.HTTP_500_INTERNAL_SERVER_ERROR
239+
)
240+
241+
242+
@router.post('/body-processing/preview')
243+
async def preview_body_processing(
244+
request: Request,
245+
preview_request: dict
246+
) -> BaseResponseMsg:
247+
"""预览Body处理结果"""
248+
try:
249+
from utils.body_field_processor import BodyFieldProcessor
250+
251+
# 提取参数
252+
body = preview_request.get('body', '')
253+
content_type = preview_request.get('content_type')
254+
target_url = preview_request.get('target_url')
255+
256+
if not body:
257+
return BaseResponseMsg(
258+
data=None,
259+
msg="Body内容不能为空",
260+
success=False,
261+
code=status.HTTP_400_BAD_REQUEST
262+
)
263+
264+
client_ip = request.client.host
265+
manager = DataStore.get_session_body_field_manager()
266+
267+
if manager is None:
268+
return BaseResponseMsg(
269+
data=None,
270+
msg="Body字段管理器不可用",
271+
success=False,
272+
code=status.HTTP_500_INTERNAL_SERVER_ERROR
273+
)
274+
275+
# 获取活跃的会话Body字段
276+
session_fields = manager.get_session_body_fields(client_ip, active_only=True)
277+
278+
# 处理Body
279+
processed_body, applied_rules = BodyFieldProcessor.process_body(
280+
body,
281+
content_type,
282+
session_fields,
283+
target_url
284+
)
285+
286+
preview_result = {
287+
"original_body": body,
288+
"processed_body": processed_body,
289+
"applied_rules": applied_rules,
290+
"changes_count": len(applied_rules)
291+
}
292+
293+
return BaseResponseMsg(
294+
data=preview_result,
295+
msg="Body处理预览成功",
296+
success=True,
297+
code=status.HTTP_200_OK
298+
)
299+
except Exception as e:
300+
logger.error(f"Failed to preview body processing: {e}")
301+
return BaseResponseMsg(
302+
data=None,
303+
msg=str(e),
304+
success=False,
305+
code=status.HTTP_500_INTERNAL_SERVER_ERROR
306+
)

src/backEnd/app.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from api.chromeExApi.admin import router as chrome_admin_router
1414
from api.burpSuiteExApi.admin import router as burp_admin_router
1515
from api.commonApi.headerController import router as header_router
16+
from api.commonApi.bodyFieldController import router as body_field_router
1617
from api.commonApi.authController import router as auth_router
1718
from api.commonApi.configController import router as config_router
1819
from api.commonApi.scanPreset import router as scan_preset_router
@@ -63,6 +64,7 @@ async def lifespan(app: FastAPI):
6364
app.include_router(chrome_admin_router, prefix="/api", tags=["chrome"])
6465
app.include_router(burp_admin_router, prefix="/api", tags=["burp"])
6566
app.include_router(header_router, prefix="/api", tags=["header"])
67+
app.include_router(body_field_router, prefix="/api/commonApi/body-field", tags=["body-field"])
6668
app.include_router(auth_router, prefix="/api", tags=["auth"])
6769
app.include_router(config_router, prefix="/api", tags=["config"])
6870
app.include_router(scan_preset_router, prefix="/api", tags=["scan-preset"])

src/backEnd/model/DataStore.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ class DataStore(object):
2626
session_header_manager = None
2727
session_header_manager_lock = threading.Lock()
2828

29+
# 会话Body字段管理器(单例模式)
30+
_session_body_field_manager: Optional['SessionBodyFieldManager'] = None
31+
_session_body_field_manager_lock = threading.Lock()
32+
2933
@classmethod
3034
def get_session_header_manager(cls):
3135
"""获取会话性请求头管理器单例"""
@@ -35,3 +39,13 @@ def get_session_header_manager(cls):
3539
from utils.session_header_manager import SessionHeaderManager
3640
cls.session_header_manager = SessionHeaderManager()
3741
return cls.session_header_manager
42+
43+
@classmethod
44+
def get_session_body_field_manager(cls) -> Optional['SessionBodyFieldManager']:
45+
"""获取会话Body字段管理器单例"""
46+
if cls._session_body_field_manager is None:
47+
with cls._session_body_field_manager_lock:
48+
if cls._session_body_field_manager is None:
49+
from utils.session_body_field_manager import SessionBodyFieldManager
50+
cls._session_body_field_manager = SessionBodyFieldManager()
51+
return cls._session_body_field_manager

0 commit comments

Comments
 (0)