From 11d00f663c45747014ba7fd32fd72f189cdba173 Mon Sep 17 00:00:00 2001 From: jaydenfyi <213395523+jaydenfyi@users.noreply.github.com> Date: Sun, 25 Jan 2026 21:35:48 +0800 Subject: [PATCH] default requireMention to true --- docs/channels/twitch.md | 16 ++--- extensions/twitch/README.md | 7 +- extensions/twitch/src/access-control.test.ts | 76 ++++++++++++++++++-- extensions/twitch/src/access-control.ts | 2 +- extensions/twitch/src/onboarding.ts | 10 +-- 5 files changed, 82 insertions(+), 29 deletions(-) diff --git a/docs/channels/twitch.md b/docs/channels/twitch.md index 5974225b7..43473bfec 100644 --- a/docs/channels/twitch.md +++ b/docs/channels/twitch.md @@ -38,7 +38,7 @@ Details: [Plugins](/plugin) - If both are set, config takes precedence (env fallback is default-account only). 4) Start the gateway. -**⚠️ Important:** Add `requireMention: true` and access control (`allowFrom` or `allowedRoles`) to prevent the bot from replying to all chat messages. +**⚠️ Important:** Add access control (`allowFrom` or `allowedRoles`) to prevent unauthorized users from triggering the bot. `requireMention` defaults to `true`. Minimal config: @@ -51,7 +51,6 @@ Minimal config: accessToken: "oauth:abc123...", // OAuth Access Token (or use CLAWDBOT_TWITCH_ACCESS_TOKEN env var) clientId: "xyz789...", // Client ID from Token Generator channel: "vevisk", // Which Twitch channel's chat to join - requireMention: true, // (recommended) Only reply when mentioned allowFrom: ["123456789"] // (recommended) Your Twitch user ID only } } @@ -106,7 +105,6 @@ If both env and config are set, config takes precedence. { channels: { twitch: { - requireMention: true, // (recommended) Only respond when mentioned allowFrom: ["123456789"], // (recommended) Your Twitch user ID only allowedRoles: ["moderator"] // Or restrict to roles } @@ -223,7 +221,9 @@ Users in `allowFrom` bypass role checks: } ``` -### Require @mention +### Disable @mention requirement + +By default, `requireMention` is `true`. To disable and respond to all messages: ```json5 { @@ -231,7 +231,7 @@ Users in `allowFrom` bypass role checks: twitch: { accounts: { default: { - requireMention: true + requireMention: false } } } @@ -287,7 +287,7 @@ If you see "token refresh disabled (no refresh token)": - `obtainmentTimestamp` - Token obtained timestamp - `allowFrom` - User ID allowlist - `allowedRoles` - Role-based access control (`"moderator" | "owner" | "vip" | "subscriber" | "all"`) -- `requireMention` - Require @mention (default: `false`) +- `requireMention` - Require @mention (default: `true`) **Provider options:** - `channels.twitch.enabled` - Enable/disable channel startup @@ -310,7 +310,6 @@ Full example: channel: "vevisk", clientSecret: "secret123...", refreshToken: "refresh456...", - requireMention: true, allowFrom: ["123456789"], allowedRoles: ["moderator", "vip"], accounts: { @@ -325,8 +324,7 @@ Full example: expiresIn: 14400, obtainmentTimestamp: 1706092800000, allowFrom: ["123456789", "987654321"], - allowedRoles: ["moderator"], - requireMention: true + allowedRoles: ["moderator"] } } } diff --git a/extensions/twitch/README.md b/extensions/twitch/README.md index f46df27d9..e514870fc 100644 --- a/extensions/twitch/README.md +++ b/extensions/twitch/README.md @@ -20,7 +20,7 @@ Onboarding: select Twitch and confirm the install prompt to fetch the plugin aut Minimal config (simplified single-account): -**⚠️ Important:** Strongly recommended to add `requireMention` and access control (`allowFrom` or `allowedRoles`) to prevent the bot from replying to all chat messages. +**⚠️ Important:** `requireMention` defaults to `true`. Add access control (`allowFrom` or `allowedRoles`) to prevent unauthorized users from triggering the bot. ```json5 { @@ -31,16 +31,15 @@ Minimal config (simplified single-account): accessToken: "oauth:abc123...", // OAuth Access Token (add oauth: prefix) clientId: "xyz789...", // Client ID from Token Generator channel: "vevisk", // Channel to join - requireMention: true, // (recommended) Only reply when mentioned allowFrom: ["123456789"], // (recommended) Your Twitch user ID only (Convert your twitch username to ID at https://www.streamweasels.com/tools/convert-twitch-username-%20to-user-id/) }, }, } ``` -**Recommended access control options:** +**Access control options:** -- `requireMention: true` - Only respond when the bot is mentioned with `@botname` +- `requireMention: false` - Disable the default mention requirement to respond to all messages - `allowFrom: ["your_user_id"]` - Restrict to your Twitch user ID only (find your ID at https://www.twitchangles.com/xqc or similar) - `allowedRoles: ["moderator", "vip", "subscriber"]` - Restrict to specific roles diff --git a/extensions/twitch/src/access-control.test.ts b/extensions/twitch/src/access-control.test.ts index 459cf0da7..1200f72db 100644 --- a/extensions/twitch/src/access-control.test.ts +++ b/extensions/twitch/src/access-control.test.ts @@ -16,9 +16,44 @@ describe("checkTwitchAccessControl", () => { }; describe("when no restrictions are configured", () => { - it("allows all messages", () => { + it("allows messages that mention the bot (default requireMention)", () => { + const message: TwitchChatMessage = { + ...mockMessage, + message: "@testbot hello", + }; const result = checkTwitchAccessControl({ - message: mockMessage, + message, + account: mockAccount, + botUsername: "testbot", + }); + expect(result.allowed).toBe(true); + }); + }); + + describe("requireMention default", () => { + it("defaults to true when undefined", () => { + const message: TwitchChatMessage = { + ...mockMessage, + message: "hello bot", + }; + + const result = checkTwitchAccessControl({ + message, + account: mockAccount, + botUsername: "testbot", + }); + expect(result.allowed).toBe(false); + expect(result.reason).toContain("does not mention the bot"); + }); + + it("allows mention when requireMention is undefined", () => { + const message: TwitchChatMessage = { + ...mockMessage, + message: "@testbot hello", + }; + + const result = checkTwitchAccessControl({ + message, account: mockAccount, botUsername: "testbot", }); @@ -85,9 +120,13 @@ describe("checkTwitchAccessControl", () => { ...mockAccount, allowFrom: ["123456", "789012"], }; + const message: TwitchChatMessage = { + ...mockMessage, + message: "@testbot hello", + }; const result = checkTwitchAccessControl({ - message: mockMessage, + message, account, botUsername: "testbot", }); @@ -101,9 +140,13 @@ describe("checkTwitchAccessControl", () => { ...mockAccount, allowFrom: ["789012"], }; + const message: TwitchChatMessage = { + ...mockMessage, + message: "@testbot hello", + }; const result = checkTwitchAccessControl({ - message: mockMessage, + message, account, botUsername: "testbot", }); @@ -116,7 +159,11 @@ describe("checkTwitchAccessControl", () => { ...mockAccount, allowFrom: ["123456"], }; - const message = { ...mockMessage, userId: undefined }; + const message: TwitchChatMessage = { + ...mockMessage, + message: "@testbot hello", + userId: undefined, + }; const result = checkTwitchAccessControl({ message, @@ -135,6 +182,7 @@ describe("checkTwitchAccessControl", () => { }; const message: TwitchChatMessage = { ...mockMessage, + message: "@testbot hello", isOwner: false, }; @@ -154,6 +202,7 @@ describe("checkTwitchAccessControl", () => { }; const message: TwitchChatMessage = { ...mockMessage, + message: "@testbot hello", userId: "123456", isMod: true, }; @@ -175,6 +224,7 @@ describe("checkTwitchAccessControl", () => { }; const message: TwitchChatMessage = { ...mockMessage, + message: "@testbot hello", userId: "123456", isMod: false, }; @@ -197,6 +247,7 @@ describe("checkTwitchAccessControl", () => { }; const message: TwitchChatMessage = { ...mockMessage, + message: "@testbot hello", isMod: true, }; @@ -216,6 +267,7 @@ describe("checkTwitchAccessControl", () => { }; const message: TwitchChatMessage = { ...mockMessage, + message: "@testbot hello", isVip: true, isMod: false, isSub: false, @@ -236,6 +288,7 @@ describe("checkTwitchAccessControl", () => { }; const message: TwitchChatMessage = { ...mockMessage, + message: "@testbot hello", isMod: false, }; @@ -253,9 +306,13 @@ describe("checkTwitchAccessControl", () => { ...mockAccount, allowedRoles: ["all"], }; + const message: TwitchChatMessage = { + ...mockMessage, + message: "@testbot hello", + }; const result = checkTwitchAccessControl({ - message: mockMessage, + message, account, botUsername: "testbot", }); @@ -270,6 +327,7 @@ describe("checkTwitchAccessControl", () => { }; const message: TwitchChatMessage = { ...mockMessage, + message: "@testbot hello", isMod: true, }; @@ -288,6 +346,7 @@ describe("checkTwitchAccessControl", () => { }; const message: TwitchChatMessage = { ...mockMessage, + message: "@testbot hello", isSub: true, }; @@ -306,6 +365,7 @@ describe("checkTwitchAccessControl", () => { }; const message: TwitchChatMessage = { ...mockMessage, + message: "@testbot hello", isOwner: true, }; @@ -324,6 +384,7 @@ describe("checkTwitchAccessControl", () => { }; const message: TwitchChatMessage = { ...mockMessage, + message: "@testbot hello", isVip: true, }; @@ -365,7 +426,8 @@ describe("checkTwitchAccessControl", () => { }; const message: TwitchChatMessage = { ...mockMessage, - isOwner: false, // Not owner, but in allowlist + message: "@testbot hello", + isOwner: false, }; const result = checkTwitchAccessControl({ diff --git a/extensions/twitch/src/access-control.ts b/extensions/twitch/src/access-control.ts index 1e985b938..0ce86d78b 100644 --- a/extensions/twitch/src/access-control.ts +++ b/extensions/twitch/src/access-control.ts @@ -38,7 +38,7 @@ export function checkTwitchAccessControl(params: { }): TwitchAccessControlResult { const { message, account, botUsername } = params; - if (account.requireMention) { + if (account.requireMention ?? true) { const mentions = extractMentions(message.message); if (!mentions.includes(botUsername.toLowerCase())) { return { diff --git a/extensions/twitch/src/onboarding.ts b/extensions/twitch/src/onboarding.ts index 14501693c..d19a0c7dd 100644 --- a/extensions/twitch/src/onboarding.ts +++ b/extensions/twitch/src/onboarding.ts @@ -269,10 +269,9 @@ const dmPolicy: ChannelOnboardingDmPolicy = { return "disabled"; }, setPolicy: (cfg, policy) => { - // Map policy to Twitch roles const allowedRoles: TwitchRole[] = policy === "open" ? ["all"] : policy === "allowlist" ? [] : ["moderator"]; - return setTwitchAccessControl(cfg as ClawdbotConfig, allowedRoles, false); + return setTwitchAccessControl(cfg as ClawdbotConfig, allowedRoles, true); }, promptAllowFrom: async ({ cfg, prompter }) => { const account = getAccountConfig(cfg, DEFAULT_ACCOUNT_ID); @@ -378,12 +377,7 @@ export const twitchOnboardingAdapter: ChannelOnboardingAdapter = { ? ["moderator", "vip"] : []; - const requireMention = accessConfig.policy === "open"; - const cfgWithAccessControl = setTwitchAccessControl( - cfgWithAllowFrom, - allowedRoles, - requireMention, - ); + const cfgWithAccessControl = setTwitchAccessControl(cfgWithAllowFrom, allowedRoles, true); return { cfg: cfgWithAccessControl }; } }