374 lines
16 KiB
Python
374 lines
16 KiB
Python
# =============================================================================
|
||
# 企微IT智能服务台 — 火绒集成数据模型
|
||
# =============================================================================
|
||
# 说明:火绒API请求/响应的 Pydantic 数据模型
|
||
# 包含:终端信息、漏洞信息、病毒事件、任务下发等
|
||
# =============================================================================
|
||
|
||
from typing import Any, Dict, List, Optional
|
||
|
||
from pydantic import BaseModel, Field, model_validator
|
||
|
||
|
||
# ==========================================================================
|
||
# 通用响应模型
|
||
# ==========================================================================
|
||
|
||
class HuorongApiResponse(BaseModel):
|
||
"""火绒API统一响应模型。
|
||
|
||
火绒所有API返回格式一致(官方API文档 v1):
|
||
成功时: { "errno": 0, "errmsg": "", "data": { ... } }
|
||
失败时: { "errno": 1, "errmsg": "Authentication failed" }
|
||
|
||
官方错误码定义:
|
||
- errno=0: 成功
|
||
- errno=1: 认证失败
|
||
- errno=2: 参数错误
|
||
- errno=3: 服务器内部错误
|
||
- errno=4: API未授权
|
||
|
||
注意:火绒API始终使用 errno(不是 errcode)。
|
||
使用 model_validator 在验证前将 errno 归一化为 errcode,
|
||
保持内部代码统一使用 errcode 字段。
|
||
|
||
Attributes:
|
||
errcode: 错误码,0表示成功(从 errno 归一化而来)
|
||
errmsg: 错误描述(成功时为空字符串)
|
||
data: 业务数据(成功时非None)
|
||
"""
|
||
|
||
@model_validator(mode='before')
|
||
@classmethod
|
||
def normalize_error_fields(cls, data: Any) -> Any:
|
||
"""将火绒API返回的 errno 字段归一化为 errcode。
|
||
|
||
火绒API在认证失败等错误场景下返回 errno 而非 errcode,
|
||
此验证器在 Pydantic 字段校验前将 errno 转换为 errcode,
|
||
统一后续处理逻辑。
|
||
|
||
Args:
|
||
data: 原始输入数据(通常为dict)
|
||
|
||
Returns:
|
||
归一化后的数据
|
||
"""
|
||
if isinstance(data, dict) and 'errno' in data and 'errcode' not in data:
|
||
data['errcode'] = data.pop('errno')
|
||
return data
|
||
|
||
errcode: int = Field(..., description="错误码,0=成功")
|
||
errmsg: str = Field(default="ok", description="错误描述")
|
||
data: Optional[Any] = Field(default=None, description="业务数据")
|
||
|
||
|
||
# ==========================================================================
|
||
# 终端基本信息 — /api/clnts/_list 返回
|
||
# ==========================================================================
|
||
|
||
class TerminalBasicInfo(BaseModel):
|
||
"""终端基本信息(_list 接口返回的每条记录)。
|
||
|
||
字段名严格按照火绒API文档实际返回值定义。
|
||
注意:API返回的字段名与之前猜测不同,已根据官方文档修正。
|
||
|
||
Attributes:
|
||
id: 内部数据库ID
|
||
client_id: 终端唯一ID(40位十六进制字符串,用于所有任务下发)
|
||
client_name: 客户端名称
|
||
computer_name: 计算机名
|
||
local_ip: 本地IP
|
||
connect_ip: 连接IP(客户端连接控制中心使用的IP)
|
||
mac: MAC地址
|
||
group_id: 分组ID
|
||
os_version: 操作系统版本
|
||
version: 火绒客户端版本
|
||
definitions: 病毒库更新时间
|
||
is_online: 在线状态
|
||
last_connect_time: 最后连接时间(Unix时间戳)
|
||
last_seen_time: 最后可见时间(Unix时间戳)
|
||
first_appear_time: 首次出现时间(Unix时间戳)
|
||
"""
|
||
id: Optional[int] = Field(default=None, description="内部数据库ID")
|
||
client_id: str = Field(..., description="终端唯一ID")
|
||
client_name: str = Field(default="", description="客户端名称")
|
||
computer_name: str = Field(default="", description="计算机名")
|
||
local_ip: str = Field(default="", description="本地IP")
|
||
connect_ip: str = Field(default="", description="连接IP")
|
||
mac: str = Field(default="", description="MAC地址")
|
||
group_id: Optional[Any] = Field(default=None, description="分组ID(int或str)")
|
||
os_version: str = Field(default="", description="操作系统版本")
|
||
version: str = Field(default="", description="火绒客户端版本")
|
||
definitions: str = Field(default="", description="病毒库更新时间")
|
||
is_online: bool = Field(default=False, description="在线状态")
|
||
last_connect_time: Optional[int] = Field(default=None, description="最后连接时间")
|
||
last_seen_time: Optional[int] = Field(default=None, description="最后可见时间")
|
||
first_appear_time: Optional[int] = Field(default=None, description="首次出现时间")
|
||
|
||
|
||
class TerminalListRequest(BaseModel):
|
||
"""终端列表查询请求。
|
||
|
||
Attributes:
|
||
group_id: 分组ID(可选,不传则查全部分组)
|
||
page: 页码(从1开始)
|
||
per_page: 每页条数
|
||
"""
|
||
group_id: Optional[str] = Field(default=None, description="分组ID")
|
||
page: int = Field(default=1, ge=1, description="页码")
|
||
per_page: int = Field(default=20, ge=1, le=100, description="每页条数")
|
||
|
||
|
||
# ==========================================================================
|
||
# 终端详细信息v2 — /api/clnts/_info2 返回
|
||
# ==========================================================================
|
||
|
||
class HardwareInfo(BaseModel):
|
||
"""终端硬件信息。
|
||
|
||
Attributes:
|
||
cpu: CPU信息
|
||
memory: 内存信息
|
||
disk: 磁盘信息
|
||
motherboard: 主板信息
|
||
network_card: 网卡信息
|
||
"""
|
||
cpu: str = Field(default="", description="CPU信息")
|
||
memory: str = Field(default="", description="内存信息")
|
||
disk: str = Field(default="", description="磁盘信息")
|
||
motherboard: str = Field(default="", description="主板信息")
|
||
network_card: str = Field(default="", description="网卡信息")
|
||
|
||
|
||
class SoftwareInfo(BaseModel):
|
||
"""已安装软件条目。
|
||
|
||
Attributes:
|
||
name: 软件名称
|
||
version: 版本号
|
||
publisher: 发布者
|
||
"""
|
||
name: str = Field(default="", description="软件名称")
|
||
version: str = Field(default="", description="版本号")
|
||
publisher: str = Field(default="", description="发布者")
|
||
|
||
|
||
class AssetInfo(BaseModel):
|
||
"""资产信息。
|
||
|
||
Attributes:
|
||
asset_tag: 资产标签
|
||
serial_number: 序列号
|
||
"""
|
||
asset_tag: str = Field(default="", description="资产标签")
|
||
serial_number: str = Field(default="", description="序列号")
|
||
|
||
|
||
class NetworkConfig(BaseModel):
|
||
"""网络配置信息。
|
||
|
||
Attributes:
|
||
ip: IP地址
|
||
gateway: 网关
|
||
dns: DNS服务器
|
||
adapter_info: 网卡适配器信息
|
||
"""
|
||
ip: str = Field(default="", description="IP地址")
|
||
gateway: str = Field(default="", description="网关")
|
||
dns: str = Field(default="", description="DNS服务器")
|
||
adapter_info: str = Field(default="", description="网卡适配器信息")
|
||
|
||
|
||
class TerminalDetailV2(BaseModel):
|
||
"""终端详细信息v2(_info2 接口返回)。
|
||
|
||
通过 optional_fields 参数指定需要返回的信息块:
|
||
- hardware: 硬件信息
|
||
- software: 已安装软件
|
||
- assets: 资产信息
|
||
- netconf: 网络配置
|
||
|
||
Attributes:
|
||
client_id: 终端唯一ID
|
||
computer_name: 计算机名
|
||
hardware: 硬件信息(可选)
|
||
software: 已安装软件列表(可选)
|
||
assets: 资产信息(可选)
|
||
netconf: 网络配置(可选)
|
||
"""
|
||
client_id: str = Field(..., description="终端唯一ID")
|
||
computer_name: str = Field(default="", description="计算机名")
|
||
hardware: Optional[HardwareInfo] = Field(default=None, description="硬件信息")
|
||
software: Optional[List[SoftwareInfo]] = Field(default=None, description="已安装软件")
|
||
assets: Optional[AssetInfo] = Field(default=None, description="资产信息")
|
||
netconf: Optional[NetworkConfig] = Field(default=None, description="网络配置")
|
||
|
||
|
||
class TerminalDetailRequest(BaseModel):
|
||
"""终端详细信息查询请求。
|
||
|
||
Attributes:
|
||
client_id: 终端唯一ID
|
||
optional_fields: 需要返回的可选信息块列表
|
||
"""
|
||
client_id: str = Field(..., description="终端唯一ID")
|
||
optional_fields: List[str] = Field(
|
||
default_factory=lambda: ["hardware", "software", "assets", "netconf"],
|
||
description="可选信息块: hardware/software/assets/netconf",
|
||
)
|
||
|
||
|
||
# ==========================================================================
|
||
# 漏洞信息 — /api/clnts/_leak 返回
|
||
# 说明:_leak 接口返回的是"存在高危漏洞未修复的终端列表",
|
||
# 每条记录是终端信息(非漏洞详情),API不返回具体漏洞CVE列表。
|
||
# 外层还有 all_client(终端总数)和 risk_client(高危终端数)统计。
|
||
# ==========================================================================
|
||
|
||
class TerminalLeakInfo(BaseModel):
|
||
"""存在高危漏洞的终端信息(_leak 接口返回的每条记录)。
|
||
|
||
注意:_leak 返回的是终端维度数据,不是漏洞维度。
|
||
字段名严格按照火绒API文档实际返回值定义。
|
||
与 _list 接口的字段名不同!
|
||
|
||
Attributes:
|
||
cid: 终端唯一ID(_leak 中叫 cid,_list 中叫 client_id)
|
||
hostname: 计算机名(_leak 中叫 hostname,_list 中叫 computer_name)
|
||
client_name: 终端名称
|
||
group_name: 分组名称
|
||
group_id: 分组ID
|
||
ip_addr: 本地IP(_leak 中叫 ip_addr,_list 中叫 local_ip)
|
||
call_ip: 连接IP(_leak 中叫 call_ip,_list 中叫 connect_ip)
|
||
mac: MAC地址
|
||
osver: 操作系统版本(_leak 中叫 osver,_list 中叫 os_version)
|
||
os_type: 终端类型(如 Windows)
|
||
prodver: 火绒客户端版本(_leak 中叫 prodver,_list 中叫 version)
|
||
virdb: 病毒库版本(Unix时间戳,_leak 中叫 virdb,_list 中叫 definitions)
|
||
stat: 在线状态码(1=离线, 2=在线, 3=异常,_list 中是 is_online 布尔值)
|
||
"""
|
||
cid: str = Field(..., description="终端唯一ID")
|
||
hostname: str = Field(default="", description="计算机名")
|
||
client_name: str = Field(default="", description="终端名称")
|
||
group_name: str = Field(default="", description="分组名称")
|
||
group_id: Optional[Any] = Field(default=None, description="分组ID")
|
||
ip_addr: str = Field(default="", description="本地IP")
|
||
call_ip: str = Field(default="", description="连接IP")
|
||
mac: str = Field(default="", description="MAC地址")
|
||
osver: str = Field(default="", description="操作系统版本")
|
||
os_type: str = Field(default="", description="终端类型")
|
||
prodver: str = Field(default="", description="火绒客户端版本")
|
||
virdb: Optional[Any] = Field(default=None, description="病毒库版本(Unix时间戳)")
|
||
stat: int = Field(default=1, description="在线状态码: 1=离线 2=在线 3=异常")
|
||
|
||
|
||
# ==========================================================================
|
||
# 病毒事件 — /api/clnts/_virus_events 返回
|
||
# 说明:_virus_events 返回终端维度的病毒日志统计,
|
||
# 含总数(count)和4种处理结果(result)的明细。
|
||
# 请求需指定 type: 0=按client_id查, 1=按group_id查, 2=查全部
|
||
# ==========================================================================
|
||
|
||
class VirusHandleResult(BaseModel):
|
||
"""病毒事件处理结果统计。
|
||
|
||
Attributes:
|
||
success: 处理成功数
|
||
fail: 处理失败数
|
||
ignored: 暂不处理数
|
||
trusted: 已信任数
|
||
"""
|
||
success: int = Field(default=0, description="处理成功数")
|
||
fail: int = Field(default=0, description="处理失败数")
|
||
ignored: int = Field(default=0, description="暂不处理数")
|
||
trusted: int = Field(default=0, description="已信任数")
|
||
|
||
|
||
class VirusEventStats(BaseModel):
|
||
"""终端病毒事件统计(_virus_events 接口返回的每条记录)。
|
||
|
||
字段名严格按照火绒API文档实际返回值定义。
|
||
与 _list 接口的字段名基本一致。
|
||
|
||
Attributes:
|
||
group_id: 分组ID
|
||
client_id: 终端唯一ID
|
||
client_name: 终端名称
|
||
computer_name: 计算机名
|
||
local_ip: 本地IP
|
||
connect_ip: 连接IP
|
||
mac: MAC地址
|
||
count: 病毒日志总数
|
||
result: 处理结果统计(success/fail/ignored/trusted)
|
||
"""
|
||
group_id: Optional[Any] = Field(default=None, description="分组ID")
|
||
client_id: str = Field(..., description="终端唯一ID")
|
||
client_name: str = Field(default="", description="终端名称")
|
||
computer_name: str = Field(default="", description="计算机名")
|
||
local_ip: str = Field(default="", description="本地IP")
|
||
connect_ip: str = Field(default="", description="连接IP")
|
||
mac: str = Field(default="", description="MAC地址")
|
||
count: int = Field(default=0, description="病毒日志总数")
|
||
result: Optional[VirusHandleResult] = Field(default=None, description="处理结果统计")
|
||
|
||
|
||
# ==========================================================================
|
||
# 终端任务 — /api/task/_create
|
||
# ==========================================================================
|
||
|
||
class TaskCreateRequest(BaseModel):
|
||
"""终端任务创建请求。
|
||
|
||
支持的任务类型:
|
||
- quick_scan: 快速扫描
|
||
- full_scan: 全盘扫描
|
||
- custom_scan: 自定义扫描
|
||
- netctrl: 终端隔离/解除
|
||
- message: 发送通知
|
||
|
||
Attributes:
|
||
task_type: 任务类型
|
||
client_ids: 目标终端ID列表
|
||
net_isolation: 是否隔离(仅 netctrl 类型有效)
|
||
message_content: 通知内容(仅 message 类型有效)
|
||
"""
|
||
task_type: str = Field(..., description="任务类型: quick_scan/full_scan/custom_scan/netctrl/message")
|
||
client_ids: List[str] = Field(..., min_length=1, description="目标终端ID列表")
|
||
net_isolation: Optional[bool] = Field(default=None, description="是否隔离(仅netctrl类型)")
|
||
message_content: Optional[str] = Field(default=None, description="通知内容(仅message类型)")
|
||
|
||
|
||
# ==========================================================================
|
||
# 终端安全画像(聚合模型,供前端直接使用)
|
||
# ==========================================================================
|
||
|
||
class TerminalSecurityProfile(BaseModel):
|
||
"""终端安全画像(聚合模型)。
|
||
|
||
将终端基本信息+安全状态聚合成一个模型,供坐席端直接展示。
|
||
|
||
Attributes:
|
||
client_id: 终端唯一ID
|
||
computer_name: 计算机名
|
||
ip: 本地IP
|
||
mac: MAC地址
|
||
os_version: 操作系统版本
|
||
is_online: 在线状态
|
||
group_name: 分组名称
|
||
hardware: 硬件概要
|
||
high_risk_leaks: 高危漏洞数
|
||
uncleaned_virus: 未处理病毒事件数
|
||
security_score: 安全评分(0-100,综合漏洞+病毒+在线状态)
|
||
"""
|
||
client_id: str = Field(..., description="终端唯一ID")
|
||
computer_name: str = Field(default="", description="计算机名")
|
||
ip: str = Field(default="", description="本地IP")
|
||
mac: str = Field(default="", description="MAC地址")
|
||
os_version: str = Field(default="", description="操作系统版本")
|
||
is_online: bool = Field(default=False, description="在线状态")
|
||
group_name: str = Field(default="", description="分组名称")
|
||
hardware: Optional[HardwareInfo] = Field(default=None, description="硬件概要")
|
||
high_risk_leaks: int = Field(default=0, description="高危漏洞数")
|
||
uncleaned_virus: int = Field(default=0, description="未处理病毒事件数")
|
||
security_score: int = Field(default=100, description="安全评分(0-100)")
|