新增 Slack 渠道扩展,支持在 Yuxi 平台中集成 Slack 团队协作平台。 包含以下功能模块: - config: 渠道配置管理 - gateway: SSE/WebSocket 网关接入 - outbound: 外发消息管理 - streaming: 流式消息处理 - pairing: 用户配对与绑定 - security: 安全校验 - monitor: 渠道状态监控 - status: 会话状态管理 - actions: 交互动作处理 - interactive: 交互式消息 - commands: 斜杠指令 - threading: 线程管理 - mentions: @提及 - constants: 常量定义 - types: 类型定义
108 lines
3.5 KiB
Python
108 lines
3.5 KiB
Python
import logging
|
|
import re
|
|
|
|
from yuxi.channel.protocols import ChannelGroupContext
|
|
from yuxi.channel.extensions.slack.constants import (
|
|
SLACK_CHANNEL_ID_PATTERN,
|
|
SLACK_DM_ID_PATTERN,
|
|
SLACK_PRIVATE_CHANNEL_ID_PATTERN,
|
|
SLACK_USER_ID_PATTERN,
|
|
SLACK_WORKSPACE_ID_PATTERN,
|
|
)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
_SLACK_ID_PATTERNS = [
|
|
re.compile(SLACK_USER_ID_PATTERN),
|
|
re.compile(SLACK_CHANNEL_ID_PATTERN),
|
|
re.compile(SLACK_PRIVATE_CHANNEL_ID_PATTERN),
|
|
re.compile(SLACK_DM_ID_PATTERN),
|
|
re.compile(SLACK_WORKSPACE_ID_PATTERN),
|
|
]
|
|
|
|
_USER_ID_RE = re.compile(SLACK_USER_ID_PATTERN)
|
|
_CHANNEL_ID_RE = re.compile(SLACK_CHANNEL_ID_PATTERN)
|
|
|
|
|
|
class SlackSecurity:
|
|
def resolve_dm_policy(self) -> dict:
|
|
return {"mode": "pairing", "allow_from": []}
|
|
|
|
async def check_allowlist(self, peer_id: str, channel_type: str) -> bool:
|
|
return True
|
|
|
|
def resolve_dm_policy_for_account(self, account: dict) -> dict:
|
|
mode = account.get("dm_policy", "pairing")
|
|
return {"mode": mode, "allow_from": account.get("allow_from", [])}
|
|
|
|
def resolve_group_policy_for_account(self, account: dict) -> dict:
|
|
mode = account.get("group_policy", "open")
|
|
return {"mode": mode, "group_allow_from": account.get("group_allow_from", [])}
|
|
|
|
def resolve_require_mention(self, ctx: ChannelGroupContext) -> bool | None:
|
|
if not ctx:
|
|
return True
|
|
|
|
config = ctx.config
|
|
group_id = ctx.group_id
|
|
|
|
if group_id:
|
|
channels_cfg = config.get("channels", {}).get("slack", {})
|
|
channel_cfg = channels_cfg.get(group_id, {})
|
|
if "requireMention" in channel_cfg:
|
|
return channel_cfg["requireMention"]
|
|
|
|
return True
|
|
|
|
def resolve_group_intro_hint(self, ctx: ChannelGroupContext) -> str | None:
|
|
return None
|
|
|
|
def resolve_tool_policy(self, ctx: ChannelGroupContext) -> dict | None:
|
|
return None
|
|
|
|
def apply_config_fixes(self, config: dict) -> dict:
|
|
config.setdefault("channels", {})
|
|
config["channels"].setdefault("slack", {})
|
|
return config
|
|
|
|
def collect_warnings(self, config: dict, account_id: str | None = None, account: dict | None = None) -> list[str]:
|
|
warnings = []
|
|
|
|
if account:
|
|
dm_policy = account.get("dm_policy", "")
|
|
group_policy = account.get("group_policy", "")
|
|
|
|
if dm_policy == "open" and not account.get("allow_from"):
|
|
warnings.append("dmPolicy is 'open' without allowFrom")
|
|
|
|
if group_policy == "open" and not account.get("group_allow_from"):
|
|
warnings.append("groupPolicy is 'open' without groupAllowFrom")
|
|
|
|
return warnings
|
|
|
|
def collect_audit_findings(
|
|
self,
|
|
config,
|
|
account_id=None,
|
|
account=None,
|
|
source_config=None,
|
|
ordered_account_ids=None,
|
|
has_explicit_account_path=False,
|
|
) -> list[dict]:
|
|
return []
|
|
|
|
def normalize_allow_entry(self, entry: str) -> str:
|
|
for prefix in ("slack:", "user:"):
|
|
if entry.lower().startswith(prefix):
|
|
entry = entry[len(prefix) :]
|
|
return entry.upper()
|
|
|
|
def is_valid_slack_id_format(self, id_str: str) -> bool:
|
|
return any(pattern.match(id_str) for pattern in _SLACK_ID_PATTERNS)
|
|
|
|
def is_valid_user_id(self, id_str: str) -> bool:
|
|
return bool(_USER_ID_RE.match(id_str))
|
|
|
|
def is_valid_channel_id(self, id_str: str) -> bool:
|
|
return bool(_CHANNEL_ID_RE.match(id_str))
|