Files
MeshSate/app/i18n_labels.py

282 lines
9.7 KiB
Python
Raw Normal View History

"""MeshSafe 统一中文标签体系。
所有控制台页面(概览 / 任务历史 / 测试靶场)共用同一套中文映射,
保证同一个后端字段在任何页面显示的名称、颜色、说明完全一致。
设计目标
--------
1. **术语统一** —— verdict / action / severity / engine / mode 全部中文化,
英文原值保留在 title 属性里供运维排查时对照。
2. **风险分级体系** —— 把「放行 / 可疑 / 恶意 / 策略拒绝 / 异常」归入
4 个风险等级(安全 / 注意 / 高危 / 故障),与策略引擎的裁决语义对齐。
3. **单一事实源** —— 新增页面或新增字段时只需在这里登记,
不用再到每个模板里写一遍 if-else。
"""
from __future__ import annotations
from typing import Any, Dict, List, Optional, Tuple
# =============================================================================
# 风险等级体系(全局统一)
# =============================================================================
#: 风险等级 → (中文名, 徽章 CSS 类, 语义说明)
RISK_LEVELS: Dict[str, Tuple[str, str, str]] = {
"safe": ("安全", "ok", "未检出任何风险信号,正常放行"),
"notice": ("注意", "warn", "存在可疑信号,建议人工确认后放行"),
"high": ("高危", "bad", "确认存在恶意特征,必须阻断"),
"fault": ("故障", "err", "检测过程异常,按安全优先策略阻断"),
"idle": ("处理中", "muted", "检测尚未完成"),
}
#: 风险等级排序(从高到低),用于排序统计
RISK_ORDER: List[str] = ["high", "notice", "fault", "safe", "idle"]
# =============================================================================
# 裁决结论(verdict)
# =============================================================================
#: verdict → (中文名, 风险等级)
VERDICT_LABELS: Dict[str, Tuple[str, str]] = {
"clean": ("放行", "safe"),
"pass": ("放行", "safe"),
"known": ("放行", "safe"),
"suspicious": ("可疑", "notice"),
"review": ("可疑", "notice"),
"malicious": ("恶意", "high"),
"reject": ("策略拒绝", "fault"),
"error": ("检测异常", "fault"),
"pending": ("处理中", "idle"),
}
# =============================================================================
# 处置动作(action)
# =============================================================================
#: action → (中文名, 风险等级)
ACTION_LABELS: Dict[str, Tuple[str, str]] = {
"pass": ("放行", "safe"),
"pass_with_flag": ("带标记放行", "notice"),
"manual_review": ("人工复核", "notice"),
"reject": ("拦截", "high"),
"reject_and_notify": ("拦截并告警", "high"),
"error": ("异常阻断", "fault"),
"pending": ("处理中", "idle"),
}
# =============================================================================
# 严重度(severity)
# =============================================================================
#: severity → (中文名, 徽章 CSS 类)
SEVERITY_LABELS: Dict[str, Tuple[str, str]] = {
"critical": ("严重", "bad"),
"high": ("高危", "bad"),
"medium": ("中危", "warn"),
"low": ("低危", "notice"),
"info": ("提示", "muted"),
}
# =============================================================================
# 检测引擎(engine)
# =============================================================================
ENGINE_LABELS: Dict[str, str] = {
"structure": "文件结构分析",
"clamav": "ClamAV 病毒库",
"document": "文档深度检测",
"keywords": "关键词匹配",
"yara": "YARA 规则匹配",
"binary": "PE/二进制分析",
"extractor": "归档解压",
}
# =============================================================================
# 扫描模式(mode)
# =============================================================================
MODE_LABELS: Dict[str, str] = {
"sync": "同步",
"async": "异步",
}
# =============================================================================
# 样本分类(测试靶场 category)
# =============================================================================
CATEGORY_LABELS: Dict[str, str] = {
"web_shell": "Webshell",
"office_macro": "Office 宏",
"windows_pe": "Windows 可执行",
"linux_malware": "Linux 恶意脚本",
"zero_tolerance": "零容忍载体",
"encrypted": "加密文档",
"negative": "阴性对照",
"unknown": "未分类",
}
# =============================================================================
# 渠道(channel)—— 摆渡来源
# =============================================================================
CHANNEL_LABELS: Dict[str, str] = {
"default": "默认通道",
"duandao": "摆渡通道",
"console_upload": "控制台上传",
"test_center": "测试靶场",
}
# =============================================================================
# 对外查询接口
# =============================================================================
def verdict_label(verdict: Any) -> str:
"""verdict → 中文名(未知值原样返回)。"""
key = str(verdict or "").strip().lower()
return VERDICT_LABELS.get(key, (str(verdict or "-"), "idle"))[0]
def verdict_risk(verdict: Any) -> str:
"""verdict → 风险等级 key。"""
key = str(verdict or "").strip().lower()
return VERDICT_LABELS.get(key, ("-", "idle"))[1]
def verdict_badge(verdict: Any) -> str:
"""verdict → 徽章 CSS 类。"""
key = str(verdict or "").strip().lower()
return RISK_LEVELS.get(verdict_risk(key), ("-", "muted"))[1]
def action_label(action: Any) -> str:
"""action → 中文名。"""
key = str(action or "").strip().lower()
return ACTION_LABELS.get(key, (str(action or "-"), "idle"))[0]
def action_risk(action: Any) -> str:
"""action → 风险等级 key。"""
key = str(action or "").strip().lower()
return ACTION_LABELS.get(key, ("-", "idle"))[1]
def action_badge(action: Any) -> str:
"""action → 徽章 CSS 类。"""
key = str(action or "").strip().lower()
return RISK_LEVELS.get(action_risk(key), ("-", "muted"))[1]
def severity_label(severity: Any) -> str:
"""severity → 中文名。"""
key = str(severity or "").strip().lower()
return SEVERITY_LABELS.get(key, (str(severity or "-"), "muted"))[0]
def severity_badge(severity: Any) -> str:
"""severity → 徽章 CSS 类。"""
key = str(severity or "").strip().lower()
return SEVERITY_LABELS.get(key, ("-", "muted"))[1]
def engine_label(engine: Any) -> str:
"""engine → 中文名。"""
key = str(engine or "").strip().lower()
return ENGINE_LABELS.get(key, str(engine or "-"))
def mode_label(mode: Any) -> str:
"""mode → 中文名。"""
key = str(mode or "").strip().lower()
return MODE_LABELS.get(key, str(mode or "-"))
def category_label(category: Any) -> str:
"""category → 中文名。"""
key = str(category or "").strip().lower()
return CATEGORY_LABELS.get(key, str(category or "-"))
def channel_label(channel: Any) -> str:
"""channel → 中文名。"""
key = str(channel or "").strip().lower()
return CHANNEL_LABELS.get(key, str(channel or "-"))
def risk_label(risk: Any) -> str:
"""风险等级 key → 中文名。"""
key = str(risk or "").strip().lower()
return RISK_LEVELS.get(key, (str(risk or "-"), "muted", ""))[0]
def risk_badge(risk: Any) -> str:
"""风险等级 key → 徽章 CSS 类。"""
key = str(risk or "").strip().lower()
return RISK_LEVELS.get(key, ("-", "muted", ""))[1]
def risk_desc(risk: Any) -> str:
"""风险等级 key → 语义说明。"""
key = str(risk or "").strip().lower()
return RISK_LEVELS.get(key, ("-", "muted", ""))[2]
# =============================================================================
# 组合辅助
# =============================================================================
def risk_matrix() -> List[Dict[str, Any]]:
"""返回完整风险等级体系(供页面渲染说明表/图例)。"""
return [
{
"key": key,
"label": RISK_LEVELS[key][0],
"badge": RISK_LEVELS[key][1],
"desc": RISK_LEVELS[key][2],
}
for key in RISK_ORDER
if key in RISK_LEVELS
]
def verdict_summary(verdict_dist: Dict[str, int]) -> List[Dict[str, Any]]:
"""把 {verdict: count} 转成按风险等级聚合的展示列表。
输出按「高危 → 注意 → 故障 → 安全 → 处理中」排序,
每项含:中文名、徽章类、计数、占比、原始 verdict key。
同风险等级内的多个 verdict 会被合并(例如 malicious 与 reject 都是高危)。
"""
total = sum(verdict_dist.values()) or 0
# 先按 verdict 映射到风险等级
buckets: Dict[str, Dict[str, Any]] = {}
for v, cnt in verdict_dist.items():
risk = verdict_risk(v)
if risk not in buckets:
buckets[risk] = {
"key": risk,
"label": risk_label(risk),
"badge": risk_badge(risk),
"desc": risk_desc(risk),
"count": 0,
"verdicts": [],
}
buckets[risk]["count"] += int(cnt)
buckets[risk]["verdicts"].append(str(v))
items = list(buckets.values())
for it in items:
it["pct"] = round(it["count"] / total * 100, 1) if total else 0.0
items.sort(key=lambda x: RISK_ORDER.index(x["key"]) if x["key"] in RISK_ORDER else 99)
return items