Spaces:
Running
Running
| import type { | |
| AllowlistMatch, | |
| ChannelGroupContext, | |
| GroupPolicy, | |
| GroupToolPolicyConfig, | |
| } from "openclaw/plugin-sdk"; | |
| import { | |
| buildChannelKeyCandidates, | |
| normalizeChannelSlug, | |
| resolveChannelEntryMatchWithFallback, | |
| resolveMentionGatingWithBypass, | |
| resolveNestedAllowlistDecision, | |
| } from "openclaw/plugin-sdk"; | |
| import type { NextcloudTalkRoomConfig } from "./types.js"; | |
| function normalizeAllowEntry(raw: string): string { | |
| return raw | |
| .trim() | |
| .toLowerCase() | |
| .replace(/^(nextcloud-talk|nc-talk|nc):/i, ""); | |
| } | |
| export function normalizeNextcloudTalkAllowlist( | |
| values: Array<string | number> | undefined, | |
| ): string[] { | |
| return (values ?? []).map((value) => normalizeAllowEntry(String(value))).filter(Boolean); | |
| } | |
| export function resolveNextcloudTalkAllowlistMatch(params: { | |
| allowFrom: Array<string | number> | undefined; | |
| senderId: string; | |
| senderName?: string | null; | |
| }): AllowlistMatch<"wildcard" | "id" | "name"> { | |
| const allowFrom = normalizeNextcloudTalkAllowlist(params.allowFrom); | |
| if (allowFrom.length === 0) { | |
| return { allowed: false }; | |
| } | |
| if (allowFrom.includes("*")) { | |
| return { allowed: true, matchKey: "*", matchSource: "wildcard" }; | |
| } | |
| const senderId = normalizeAllowEntry(params.senderId); | |
| if (allowFrom.includes(senderId)) { | |
| return { allowed: true, matchKey: senderId, matchSource: "id" }; | |
| } | |
| const senderName = params.senderName ? normalizeAllowEntry(params.senderName) : ""; | |
| if (senderName && allowFrom.includes(senderName)) { | |
| return { allowed: true, matchKey: senderName, matchSource: "name" }; | |
| } | |
| return { allowed: false }; | |
| } | |
| export type NextcloudTalkRoomMatch = { | |
| roomConfig?: NextcloudTalkRoomConfig; | |
| wildcardConfig?: NextcloudTalkRoomConfig; | |
| roomKey?: string; | |
| matchSource?: "direct" | "parent" | "wildcard"; | |
| allowed: boolean; | |
| allowlistConfigured: boolean; | |
| }; | |
| export function resolveNextcloudTalkRoomMatch(params: { | |
| rooms?: Record<string, NextcloudTalkRoomConfig>; | |
| roomToken: string; | |
| roomName?: string | null; | |
| }): NextcloudTalkRoomMatch { | |
| const rooms = params.rooms ?? {}; | |
| const allowlistConfigured = Object.keys(rooms).length > 0; | |
| const roomName = params.roomName?.trim() || undefined; | |
| const roomCandidates = buildChannelKeyCandidates( | |
| params.roomToken, | |
| roomName, | |
| roomName ? normalizeChannelSlug(roomName) : undefined, | |
| ); | |
| const match = resolveChannelEntryMatchWithFallback({ | |
| entries: rooms, | |
| keys: roomCandidates, | |
| wildcardKey: "*", | |
| normalizeKey: normalizeChannelSlug, | |
| }); | |
| const roomConfig = match.entry; | |
| const allowed = resolveNestedAllowlistDecision({ | |
| outerConfigured: allowlistConfigured, | |
| outerMatched: Boolean(roomConfig), | |
| innerConfigured: false, | |
| innerMatched: false, | |
| }); | |
| return { | |
| roomConfig, | |
| wildcardConfig: match.wildcardEntry, | |
| roomKey: match.matchKey ?? match.key, | |
| matchSource: match.matchSource, | |
| allowed, | |
| allowlistConfigured, | |
| }; | |
| } | |
| export function resolveNextcloudTalkGroupToolPolicy( | |
| params: ChannelGroupContext, | |
| ): GroupToolPolicyConfig | undefined { | |
| const cfg = params.cfg as { | |
| channels?: { "nextcloud-talk"?: { rooms?: Record<string, NextcloudTalkRoomConfig> } }; | |
| }; | |
| const roomToken = params.groupId?.trim(); | |
| if (!roomToken) { | |
| return undefined; | |
| } | |
| const roomName = params.groupChannel?.trim() || undefined; | |
| const match = resolveNextcloudTalkRoomMatch({ | |
| rooms: cfg.channels?.["nextcloud-talk"]?.rooms, | |
| roomToken, | |
| roomName, | |
| }); | |
| return match.roomConfig?.tools ?? match.wildcardConfig?.tools; | |
| } | |
| export function resolveNextcloudTalkRequireMention(params: { | |
| roomConfig?: NextcloudTalkRoomConfig; | |
| wildcardConfig?: NextcloudTalkRoomConfig; | |
| }): boolean { | |
| if (typeof params.roomConfig?.requireMention === "boolean") { | |
| return params.roomConfig.requireMention; | |
| } | |
| if (typeof params.wildcardConfig?.requireMention === "boolean") { | |
| return params.wildcardConfig.requireMention; | |
| } | |
| return true; | |
| } | |
| export function resolveNextcloudTalkGroupAllow(params: { | |
| groupPolicy: GroupPolicy; | |
| outerAllowFrom: Array<string | number> | undefined; | |
| innerAllowFrom: Array<string | number> | undefined; | |
| senderId: string; | |
| senderName?: string | null; | |
| }): { allowed: boolean; outerMatch: AllowlistMatch; innerMatch: AllowlistMatch } { | |
| if (params.groupPolicy === "disabled") { | |
| return { allowed: false, outerMatch: { allowed: false }, innerMatch: { allowed: false } }; | |
| } | |
| if (params.groupPolicy === "open") { | |
| return { allowed: true, outerMatch: { allowed: true }, innerMatch: { allowed: true } }; | |
| } | |
| const outerAllow = normalizeNextcloudTalkAllowlist(params.outerAllowFrom); | |
| const innerAllow = normalizeNextcloudTalkAllowlist(params.innerAllowFrom); | |
| if (outerAllow.length === 0 && innerAllow.length === 0) { | |
| return { allowed: false, outerMatch: { allowed: false }, innerMatch: { allowed: false } }; | |
| } | |
| const outerMatch = resolveNextcloudTalkAllowlistMatch({ | |
| allowFrom: params.outerAllowFrom, | |
| senderId: params.senderId, | |
| senderName: params.senderName, | |
| }); | |
| const innerMatch = resolveNextcloudTalkAllowlistMatch({ | |
| allowFrom: params.innerAllowFrom, | |
| senderId: params.senderId, | |
| senderName: params.senderName, | |
| }); | |
| const allowed = resolveNestedAllowlistDecision({ | |
| outerConfigured: outerAllow.length > 0 || innerAllow.length > 0, | |
| outerMatched: outerAllow.length > 0 ? outerMatch.allowed : true, | |
| innerConfigured: innerAllow.length > 0, | |
| innerMatched: innerMatch.allowed, | |
| }); | |
| return { allowed, outerMatch, innerMatch }; | |
| } | |
| export function resolveNextcloudTalkMentionGate(params: { | |
| isGroup: boolean; | |
| requireMention: boolean; | |
| wasMentioned: boolean; | |
| allowTextCommands: boolean; | |
| hasControlCommand: boolean; | |
| commandAuthorized: boolean; | |
| }): { shouldSkip: boolean; shouldBypassMention: boolean } { | |
| const result = resolveMentionGatingWithBypass({ | |
| isGroup: params.isGroup, | |
| requireMention: params.requireMention, | |
| canDetectMention: true, | |
| wasMentioned: params.wasMentioned, | |
| allowTextCommands: params.allowTextCommands, | |
| hasControlCommand: params.hasControlCommand, | |
| commandAuthorized: params.commandAuthorized, | |
| }); | |
| return { shouldSkip: result.shouldSkip, shouldBypassMention: result.shouldBypassMention }; | |
| } | |