ForcePilot/backend/package/yuxi/channels/adapters/nextcloudtalk/secret_contract.py
Kris b018ad25da feat(backend): add Nextcloud Talk channel adapter implementation
实现了完整的Nextcloud Talk聊天适配器,包含以下核心功能:
1. 基础客户端通信与认证
2. 会话路由与聊天类型解析
3. 消息分块与格式转换
4. 用户配对与权限校验
5. 轮询式消息监听
6. 配置验证与诊断工具
7. 安全策略与去重缓存
8. 指标统计与状态快照

新增配套的配对用户缓存文件与模块导出入口。
2026-05-12 00:47:06 +08:00

82 lines
2.8 KiB
Python

from __future__ import annotations
import logging
import os
from typing import Any
logger = logging.getLogger(__name__)
SECRET_TARGETS = [
{"key": "bot_user", "label": "Bot Username", "source": "direct", "secret": False},
{"key": "app_password", "label": "App Password", "source": "direct", "secret": True},
{"key": "api_user", "label": "API Username", "source": "direct", "secret": False},
{"key": "api_password", "label": "API Password", "source": "direct", "secret": True},
{"key": "bot_secret_file", "label": "Bot Secret File", "source": "file", "secret": True},
{"key": "NEXTCLOUD_TALK_BOT_USER", "label": "Env: NEXTCLOUD_TALK_BOT_USER", "source": "env", "secret": False},
{
"key": "NEXTCLOUD_TALK_APP_PASSWORD",
"label": "Env: NEXTCLOUD_TALK_APP_PASSWORD",
"source": "env",
"secret": True,
},
{
"key": "NEXTCLOUD_TALK_API_PASSWORD",
"label": "Env: NEXTCLOUD_TALK_API_PASSWORD",
"source": "env",
"secret": True,
},
{
"key": "NEXTCLOUD_TALK_BOT_SECRET",
"label": "Env: NEXTCLOUD_TALK_BOT_SECRET",
"source": "env",
"secret": True,
},
]
def list_secret_targets() -> list[dict[str, Any]]:
return SECRET_TARGETS
def collect_runtime_secrets(config: dict[str, Any]) -> dict[str, Any]:
secrets: dict[str, Any] = {}
bot_user = config.get("bot_user", config.get("botUser", ""))
app_password = config.get("app_password", config.get("appPassword", ""))
api_user = config.get("api_user", "")
api_password = config.get("api_password", "")
if not bot_user:
bot_user = os.getenv("NEXTCLOUD_TALK_BOT_USER", "")
if not app_password:
app_password = os.getenv(
"NEXTCLOUD_TALK_APP_PASSWORD",
os.getenv("NEXTCLOUD_TALK_API_PASSWORD", os.getenv("NEXTCLOUD_TALK_BOT_SECRET", "")),
)
secrets["bot_user"] = {"value": bot_user, "present": bool(bot_user)}
secrets["app_password"] = {"value": "***" if app_password else "", "present": bool(app_password)}
secrets["api_user"] = {"value": api_user, "present": bool(api_user)}
secrets["api_password"] = {"value": "***" if api_password else "", "present": bool(api_password)}
return secrets
def verify_secret_contract(config: dict[str, Any]) -> dict[str, Any]:
result: dict[str, Any] = {"valid": True, "issues": []}
secrets = collect_runtime_secrets(config)
if not secrets["bot_user"]["present"]:
result["valid"] = False
result["issues"].append("bot_user is missing")
if not secrets["app_password"]["present"]:
result["valid"] = False
result["issues"].append("app_password is missing")
server_url = config.get("server_url", "")
if not server_url:
result["valid"] = False
result["issues"].append("server_url is missing")
return result