import type { AllowlistMatch, ChannelGroupContext, GroupPolicy, GroupToolPolicyConfig, MSTeamsChannelConfig, MSTeamsConfig, MSTeamsReplyStyle, MSTeamsTeamConfig, } from "../runtime-api.js"; import { buildChannelKeyCandidates, evaluateSenderGroupAccessForPolicy, normalizeChannelSlug, resolveAllowlistMatchSimple, resolveToolsBySender, resolveChannelEntryMatchWithFallback, resolveNestedAllowlistDecision, isDangerousNameMatchingEnabled, } from "../runtime-api.js"; export type MSTeamsResolvedRouteConfig = { teamConfig?: MSTeamsTeamConfig; channelConfig?: MSTeamsChannelConfig; allowlistConfigured: boolean; allowed: boolean; teamKey?: string; channelKey?: string; channelMatchKey?: string; channelMatchSource?: "direct" | "wildcard"; }; export function resolveMSTeamsRouteConfig(params: { cfg?: MSTeamsConfig; teamId?: string | null | undefined; teamName?: string | null | undefined; conversationId?: string | null | undefined; channelName?: string | null | undefined; allowNameMatching?: boolean; }): MSTeamsResolvedRouteConfig { const teamId = params.teamId?.trim(); const teamName = params.teamName?.trim(); const conversationId = params.conversationId?.trim(); const channelName = params.channelName?.trim(); const teams = params.cfg?.teams ?? {}; const allowlistConfigured = Object.keys(teams).length > 0; const teamCandidates = buildChannelKeyCandidates( teamId, params.allowNameMatching ? teamName : undefined, params.allowNameMatching && teamName ? normalizeChannelSlug(teamName) : undefined, ); const teamMatch = resolveChannelEntryMatchWithFallback({ entries: teams, keys: teamCandidates, wildcardKey: "*", normalizeKey: normalizeChannelSlug, }); const teamConfig = teamMatch.entry; const channels = teamConfig?.channels ?? {}; const channelAllowlistConfigured = Object.keys(channels).length > 0; const channelCandidates = buildChannelKeyCandidates( conversationId, params.allowNameMatching ? channelName : undefined, params.allowNameMatching && channelName ? normalizeChannelSlug(channelName) : undefined, ); const channelMatch = resolveChannelEntryMatchWithFallback({ entries: channels, keys: channelCandidates, wildcardKey: "*", normalizeKey: normalizeChannelSlug, }); const channelConfig = channelMatch.entry; const allowed = resolveNestedAllowlistDecision({ outerConfigured: allowlistConfigured, outerMatched: Boolean(teamConfig), innerConfigured: channelAllowlistConfigured, innerMatched: Boolean(channelConfig), }); return { teamConfig, channelConfig, allowlistConfigured, allowed, teamKey: teamMatch.matchKey ?? teamMatch.key, channelKey: channelMatch.matchKey ?? channelMatch.key, channelMatchKey: channelMatch.matchKey, channelMatchSource: channelMatch.matchSource === "direct" || channelMatch.matchSource === "wildcard" ? channelMatch.matchSource : undefined, }; } export function resolveMSTeamsGroupToolPolicy( params: ChannelGroupContext, ): GroupToolPolicyConfig | undefined { const cfg = params.cfg.channels?.msteams; if (!cfg) { return undefined; } const groupId = params.groupId?.trim(); const groupChannel = params.groupChannel?.trim(); const groupSpace = params.groupSpace?.trim(); const allowNameMatching = isDangerousNameMatchingEnabled(cfg); const resolved = resolveMSTeamsRouteConfig({ cfg, teamId: groupSpace, teamName: groupSpace, conversationId: groupId, channelName: groupChannel, allowNameMatching, }); if (resolved.channelConfig) { const senderPolicy = resolveToolsBySender({ toolsBySender: resolved.channelConfig.toolsBySender, senderId: params.senderId, senderName: params.senderName, senderUsername: params.senderUsername, senderE164: params.senderE164, }); if (senderPolicy) { return senderPolicy; } if (resolved.channelConfig.tools) { return resolved.channelConfig.tools; } const teamSenderPolicy = resolveToolsBySender({ toolsBySender: resolved.teamConfig?.toolsBySender, senderId: params.senderId, senderName: params.senderName, senderUsername: params.senderUsername, senderE164: params.senderE164, }); if (teamSenderPolicy) { return teamSenderPolicy; } return resolved.teamConfig?.tools; } if (resolved.teamConfig) { const teamSenderPolicy = resolveToolsBySender({ toolsBySender: resolved.teamConfig.toolsBySender, senderId: params.senderId, senderName: params.senderName, senderUsername: params.senderUsername, senderE164: params.senderE164, }); if (teamSenderPolicy) { return teamSenderPolicy; } if (resolved.teamConfig.tools) { return resolved.teamConfig.tools; } } if (!groupId) { return undefined; } const channelCandidates = buildChannelKeyCandidates( groupId, allowNameMatching ? groupChannel : undefined, allowNameMatching && groupChannel ? normalizeChannelSlug(groupChannel) : undefined, ); for (const teamConfig of Object.values(cfg.teams ?? {})) { const match = resolveChannelEntryMatchWithFallback({ entries: teamConfig?.channels ?? {}, keys: channelCandidates, wildcardKey: "*", normalizeKey: normalizeChannelSlug, }); if (match.entry) { const senderPolicy = resolveToolsBySender({ toolsBySender: match.entry.toolsBySender, senderId: params.senderId, senderName: params.senderName, senderUsername: params.senderUsername, senderE164: params.senderE164, }); if (senderPolicy) { return senderPolicy; } if (match.entry.tools) { return match.entry.tools; } const teamSenderPolicy = resolveToolsBySender({ toolsBySender: teamConfig?.toolsBySender, senderId: params.senderId, senderName: params.senderName, senderUsername: params.senderUsername, senderE164: params.senderE164, }); if (teamSenderPolicy) { return teamSenderPolicy; } return teamConfig?.tools; } } return undefined; } export type MSTeamsReplyPolicy = { requireMention: boolean; replyStyle: MSTeamsReplyStyle; }; export type MSTeamsAllowlistMatch = AllowlistMatch<"wildcard" | "id" | "name">; export function resolveMSTeamsAllowlistMatch(params: { allowFrom: Array; senderId: string; senderName?: string | null; allowNameMatching?: boolean; }): MSTeamsAllowlistMatch { return resolveAllowlistMatchSimple(params); } export function resolveMSTeamsReplyPolicy(params: { isDirectMessage: boolean; globalConfig?: MSTeamsConfig; teamConfig?: MSTeamsTeamConfig; channelConfig?: MSTeamsChannelConfig; }): MSTeamsReplyPolicy { if (params.isDirectMessage) { return { requireMention: false, replyStyle: "thread" }; } const requireMention = params.channelConfig?.requireMention ?? params.teamConfig?.requireMention ?? params.globalConfig?.requireMention ?? true; const explicitReplyStyle = params.channelConfig?.replyStyle ?? params.teamConfig?.replyStyle ?? params.globalConfig?.replyStyle; const replyStyle: MSTeamsReplyStyle = explicitReplyStyle ?? (requireMention ? "thread" : "top-level"); return { requireMention, replyStyle }; } export function isMSTeamsGroupAllowed(params: { groupPolicy: GroupPolicy; allowFrom: Array; senderId: string; senderName?: string | null; allowNameMatching?: boolean; }): boolean { return evaluateSenderGroupAccessForPolicy({ groupPolicy: params.groupPolicy, groupAllowFrom: params.allowFrom.map((entry) => String(entry)), senderId: params.senderId, isSenderAllowed: () => resolveMSTeamsAllowlistMatch(params).allowed, }).allowed; }