const collectSynologyChatSecurityWarnings =
createConditionalWarningCollector<ResolvedSynologyChatAccount>(
(account) =>
!account.token && "- Synology Chat: token is not configured. The webhook will reject all requests.",
(account) =>
!account.incomingUrl && "- Synology Chat: incomingUrl is not configured. The bot cannot send replies.",
(account) =>
account.allowInsecureSsl && "- Synology Chat: SSL verification is disabled (allowInsecureSsl=true). Only use this for local NAS with self-signed certificates.",
(account) =>
account.dangerouslyAllowNameMatching && "- Synology Chat: dangerouslyAllowNameMatching=true re-enables mutable username/nickname recipient matching for replies. Prefer stable numeric user IDs.",
(account) =>
account.dangerouslyAllowInheritedWebhookPath &&
account.webhookPathSource === "inherited-base" && "- Synology Chat: dangerouslyAllowInheritedWebhookPath=true opts a named account into a shared inherited webhook path. Prefer an explicit per-account webhookPath.",
(account) =>
account.dmPolicy === "open" && '- Synology Chat: dmPolicy="open" allows any user to message the bot. Consider "allowlist" for production use.',
(account) =>
account.dmPolicy === "allowlist" &&
account.allowedUserIds.length === 0 && '- Synology Chat: dmPolicy="allowlist" with empty allowedUserIds blocks all senders. Add users or set dmPolicy="open".',
);
log?.info?.(`Registered HTTP route: ${account.webhookPath} for Synology Chat`);
// Keep alive until abort signal fires. // The gateway expects a Promise that stays pending while the channel is running. // Resolving immediately triggers a restart loop. return waitUntilAbort(abortSignal, () => {
log?.info?.(`Stopping Synology Chat channel (account: ${accountId})`);
unregister();
});
},
stopAccount: async (ctx: SynologyChannelGatewayContext) => {
ctx.log?.info?.(`Synology Chat account ${ctx.accountId} stopped`);
},
},
agentPrompt: {
messageToolHints: () => [ "", "### Synology Chat Formatting", "Synology Chat supports limited formatting. Use these patterns:", "", "**Links**: Use `<URL|display text>` to create clickable links.", " Example: `<https://example.com|Click here>` renders as a clickable link.", "", "**File sharing**: Include a publicly accessible URL to share files or images.", " The NAS will download and attach the file (max 32 MB).", "", "**Limitations**:", "- No markdown, bold, italic, or code blocks", "- No buttons, cards, or interactive elements", "- No message editing after send", "- Keep messages under 2000 characters for best readability", "", "**Best practices**:", "- Use short, clear responses (Synology Chat has a minimal UI)", "- Use line breaks to separate sections", "- Use numbered or bulleted lists for clarity", "- Wrap URLs with `<URL|label>` for user-friendly links",
],
},
},
pairing: {
text: {
idLabel: "synologyChatUserId",
message: "OpenClaw: your access has been approved.",
normalizeAllowEntry: (entry: string) => normalizeLowercaseStringOrEmpty(entry),
notify: async ({ cfg, id, message }) => { const account = resolveAccount(cfg); if (!account.incomingUrl) { return;
}
await sendMessage(account.incomingUrl, message, id, account.allowInsecureSsl);
},
},
},
security: {
resolveDmPolicy: resolveSynologyChatDmPolicy,
collectWarnings: composeWarningCollectors(
projectAccountWarningCollector<ResolvedSynologyChatAccount, SynologySecurityWarningContext>(
collectSynologyChatSecurityWarnings,
),
collectSynologyChatRoutingWarnings,
),
collectAuditFindings: collectSynologyChatSecurityAuditFindings,
},
outbound: {
deliveryMode: "gateway" as const,
textChunkLimit: 2000,
sendText: async ({ to, text, accountId, cfg }: SynologyChannelSendTextContext) => { const account = resolveOutboundAccount(cfg ?? {}, accountId); const incomingUrl = requireIncomingUrl(account); const ok = await sendMessage(incomingUrl, text, to, account.allowInsecureSsl); if (!ok) { thrownew Error("Failed to send message to Synology Chat");
} return attachChannelToResult(CHANNEL_ID, { messageId: `sc-${Date.now()}`, chatId: to });
},
const ok = await sendFileUrl(incomingUrl, mediaUrl, to, account.allowInsecureSsl); if (!ok) { thrownew Error("Failed to send media to Synology Chat");
} return attachChannelToResult(CHANNEL_ID, { messageId: `sc-${Date.now()}`, chatId: to });
},
},
}) as unknown as SynologyChatPlugin;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.