Files
wecom_it_smart_desk/backend/app/services/security_comparison.py
T

150 lines
5.0 KiB
Python
Raw Normal View History

"""
终端安全对比服务 - 火绒 vs 联软
功能:
1. 获取未安装火绒的电脑清单
2. 定时任务推送
3. 手动触发
依赖:
- 联软 LV7000: get_dev_all_info()
- 火绒企业版: list_terminals()
比对逻辑:按主机名精确匹配
"""
from datetime import datetime
from typing import Optional
import logging
from app.integrations.huorong.client import HuorongClient
from app.integrations.lianruan.client import LianruanClient
logger = logging.getLogger(__name__)
class TerminalSecurityComparison:
"""终端安全对比服务"""
def __init__(self):
self.huorong = HuorongClient()
self.lianruan = LianruanClient()
async def close(self):
"""关闭连接"""
await self.huorong.close()
await self.lianruan.close()
async def get_no_huorong_devices(self) -> list[dict]:
"""获取未安装火绒的电脑清单(按主机名匹配)"""
logger.info("开始比对终端安全数据...")
# 1. 获取联软所有设备
lianruan_devices = await self._get_all_lianruan_devices()
logger.info(f"联软设备数: {len(lianruan_devices)}")
# 2. 获取火绒所有终端
huorong_devices = await self._get_all_huorong_devices()
logger.info(f"火绒终端数: {len(huorong_devices)}")
# 3. 构建火绒主机名集合(转小写匹配)
huorong_hostnames = {
dev.get("hostname", "").lower()
for dev in huorong_devices
if dev.get("hostname")
}
# 4. 比对:联软有,火绒无 = 未安装火绒
no_huorong = []
for dev in lianruan_devices:
# 联软用 strdevname (计算机名)
hostname = dev.get("strdevname", "").lower()
if hostname and hostname not in huorong_hostnames:
no_huorong.append({
"hostname": dev.get("strdevname"),
"ip": dev.get("strip1"), # 联软IP字段
"useraccount": dev.get("strusername"), # 用户名
"dept": dev.get("strdeptname"), # 部门
"last_login": dev.get("dtlastlogin"),
"osver": dev.get("strosver"),
"status": dev.get("strstatus"),
})
logger.info(f"未安装火绒设备数: {len(no_huorong)}")
return no_huorong
async def _get_all_lianruan_devices(self) -> list[dict]:
"""获取联软所有设备"""
# TODO: 分页获取全部设备
result = await self.lianruan.get_dev_all_info()
if result and hasattr(result, 'devices') and result.devices:
# 转换为字典列表
return [d.model_dump() if hasattr(d, 'model_dump') else d for d in result.devices]
return []
async def _get_all_huorong_devices(self) -> list[dict]:
"""获取火绒所有终端(分页获取)"""
all_devices = []
page = 1
per_page = 200
while True:
result = await self.huorong.list_terminals(page=page, per_page=per_page)
clients = result.get("clients", [])
if not clients:
break
for c in clients:
# 火绒字段:hostname, computer_name, ip_addr, local_ip
all_devices.append({
"hostname": c.get("hostname") or c.get("computer_name"),
"ip": c.get("ip_addr") or c.get("local_ip"),
"status": c.get("stat"),
})
# 检查是否还有更多
if len(clients) < per_page:
break
page += 1
return all_devices
async def compare_summary(self) -> dict:
"""比对汇总数据"""
lianruan_devices = await self._get_all_lianruan_devices()
huorong_devices = await self._get_all_huorong_devices()
no_huorong = await self.get_no_huorong_devices()
return {
"lianruan_count": len(lianruan_devices),
"huorong_count": len(huorong_devices),
"no_huorong_count": len(no_huorong),
"compliance_rate": f"{len(huorong_devices)/len(lianruan_devices)*100:.1f}%" if lianruan_devices else "N/A",
"generated_at": datetime.now().isoformat(),
}
class ComparisonTaskConfig:
"""定时任务配置"""
def __init__(self):
self.tasks: dict[str, dict] = {}
def add_task(self, task_id: str, config: dict):
self.tasks[task_id] = config
def get_task(self, task_id: str) -> Optional[dict]:
return self.tasks.get(task_id)
def list_tasks(self) -> list[dict]:
return [{"task_id": k, **v} for k, v in self.tasks.items()]
def delete_task(self, task_id: str) -> bool:
if task_id in self.tasks:
del self.tasks[task_id]
return True
return False
comparison_task_config = ComparisonTaskConfig()