default requireMention to true
This commit is contained in:
parent
ad828b9f0b
commit
11d00f663c
@ -38,7 +38,7 @@ Details: [Plugins](/plugin)
|
|||||||
- If both are set, config takes precedence (env fallback is default-account only).
|
- If both are set, config takes precedence (env fallback is default-account only).
|
||||||
4) Start the gateway.
|
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:
|
Minimal config:
|
||||||
|
|
||||||
@ -51,7 +51,6 @@ Minimal config:
|
|||||||
accessToken: "oauth:abc123...", // OAuth Access Token (or use CLAWDBOT_TWITCH_ACCESS_TOKEN env var)
|
accessToken: "oauth:abc123...", // OAuth Access Token (or use CLAWDBOT_TWITCH_ACCESS_TOKEN env var)
|
||||||
clientId: "xyz789...", // Client ID from Token Generator
|
clientId: "xyz789...", // Client ID from Token Generator
|
||||||
channel: "vevisk", // Which Twitch channel's chat to join
|
channel: "vevisk", // Which Twitch channel's chat to join
|
||||||
requireMention: true, // (recommended) Only reply when mentioned
|
|
||||||
allowFrom: ["123456789"] // (recommended) Your Twitch user ID only
|
allowFrom: ["123456789"] // (recommended) Your Twitch user ID only
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -106,7 +105,6 @@ If both env and config are set, config takes precedence.
|
|||||||
{
|
{
|
||||||
channels: {
|
channels: {
|
||||||
twitch: {
|
twitch: {
|
||||||
requireMention: true, // (recommended) Only respond when mentioned
|
|
||||||
allowFrom: ["123456789"], // (recommended) Your Twitch user ID only
|
allowFrom: ["123456789"], // (recommended) Your Twitch user ID only
|
||||||
allowedRoles: ["moderator"] // Or restrict to roles
|
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
|
```json5
|
||||||
{
|
{
|
||||||
@ -231,7 +231,7 @@ Users in `allowFrom` bypass role checks:
|
|||||||
twitch: {
|
twitch: {
|
||||||
accounts: {
|
accounts: {
|
||||||
default: {
|
default: {
|
||||||
requireMention: true
|
requireMention: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -287,7 +287,7 @@ If you see "token refresh disabled (no refresh token)":
|
|||||||
- `obtainmentTimestamp` - Token obtained timestamp
|
- `obtainmentTimestamp` - Token obtained timestamp
|
||||||
- `allowFrom` - User ID allowlist
|
- `allowFrom` - User ID allowlist
|
||||||
- `allowedRoles` - Role-based access control (`"moderator" | "owner" | "vip" | "subscriber" | "all"`)
|
- `allowedRoles` - Role-based access control (`"moderator" | "owner" | "vip" | "subscriber" | "all"`)
|
||||||
- `requireMention` - Require @mention (default: `false`)
|
- `requireMention` - Require @mention (default: `true`)
|
||||||
|
|
||||||
**Provider options:**
|
**Provider options:**
|
||||||
- `channels.twitch.enabled` - Enable/disable channel startup
|
- `channels.twitch.enabled` - Enable/disable channel startup
|
||||||
@ -310,7 +310,6 @@ Full example:
|
|||||||
channel: "vevisk",
|
channel: "vevisk",
|
||||||
clientSecret: "secret123...",
|
clientSecret: "secret123...",
|
||||||
refreshToken: "refresh456...",
|
refreshToken: "refresh456...",
|
||||||
requireMention: true,
|
|
||||||
allowFrom: ["123456789"],
|
allowFrom: ["123456789"],
|
||||||
allowedRoles: ["moderator", "vip"],
|
allowedRoles: ["moderator", "vip"],
|
||||||
accounts: {
|
accounts: {
|
||||||
@ -325,8 +324,7 @@ Full example:
|
|||||||
expiresIn: 14400,
|
expiresIn: 14400,
|
||||||
obtainmentTimestamp: 1706092800000,
|
obtainmentTimestamp: 1706092800000,
|
||||||
allowFrom: ["123456789", "987654321"],
|
allowFrom: ["123456789", "987654321"],
|
||||||
allowedRoles: ["moderator"],
|
allowedRoles: ["moderator"]
|
||||||
requireMention: true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,7 +20,7 @@ Onboarding: select Twitch and confirm the install prompt to fetch the plugin aut
|
|||||||
|
|
||||||
Minimal config (simplified single-account):
|
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
|
```json5
|
||||||
{
|
{
|
||||||
@ -31,16 +31,15 @@ Minimal config (simplified single-account):
|
|||||||
accessToken: "oauth:abc123...", // OAuth Access Token (add oauth: prefix)
|
accessToken: "oauth:abc123...", // OAuth Access Token (add oauth: prefix)
|
||||||
clientId: "xyz789...", // Client ID from Token Generator
|
clientId: "xyz789...", // Client ID from Token Generator
|
||||||
channel: "vevisk", // Channel to join
|
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/)
|
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)
|
- `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
|
- `allowedRoles: ["moderator", "vip", "subscriber"]` - Restrict to specific roles
|
||||||
|
|
||||||
|
|||||||
@ -16,9 +16,44 @@ describe("checkTwitchAccessControl", () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
describe("when no restrictions are configured", () => {
|
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({
|
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,
|
account: mockAccount,
|
||||||
botUsername: "testbot",
|
botUsername: "testbot",
|
||||||
});
|
});
|
||||||
@ -85,9 +120,13 @@ describe("checkTwitchAccessControl", () => {
|
|||||||
...mockAccount,
|
...mockAccount,
|
||||||
allowFrom: ["123456", "789012"],
|
allowFrom: ["123456", "789012"],
|
||||||
};
|
};
|
||||||
|
const message: TwitchChatMessage = {
|
||||||
|
...mockMessage,
|
||||||
|
message: "@testbot hello",
|
||||||
|
};
|
||||||
|
|
||||||
const result = checkTwitchAccessControl({
|
const result = checkTwitchAccessControl({
|
||||||
message: mockMessage,
|
message,
|
||||||
account,
|
account,
|
||||||
botUsername: "testbot",
|
botUsername: "testbot",
|
||||||
});
|
});
|
||||||
@ -101,9 +140,13 @@ describe("checkTwitchAccessControl", () => {
|
|||||||
...mockAccount,
|
...mockAccount,
|
||||||
allowFrom: ["789012"],
|
allowFrom: ["789012"],
|
||||||
};
|
};
|
||||||
|
const message: TwitchChatMessage = {
|
||||||
|
...mockMessage,
|
||||||
|
message: "@testbot hello",
|
||||||
|
};
|
||||||
|
|
||||||
const result = checkTwitchAccessControl({
|
const result = checkTwitchAccessControl({
|
||||||
message: mockMessage,
|
message,
|
||||||
account,
|
account,
|
||||||
botUsername: "testbot",
|
botUsername: "testbot",
|
||||||
});
|
});
|
||||||
@ -116,7 +159,11 @@ describe("checkTwitchAccessControl", () => {
|
|||||||
...mockAccount,
|
...mockAccount,
|
||||||
allowFrom: ["123456"],
|
allowFrom: ["123456"],
|
||||||
};
|
};
|
||||||
const message = { ...mockMessage, userId: undefined };
|
const message: TwitchChatMessage = {
|
||||||
|
...mockMessage,
|
||||||
|
message: "@testbot hello",
|
||||||
|
userId: undefined,
|
||||||
|
};
|
||||||
|
|
||||||
const result = checkTwitchAccessControl({
|
const result = checkTwitchAccessControl({
|
||||||
message,
|
message,
|
||||||
@ -135,6 +182,7 @@ describe("checkTwitchAccessControl", () => {
|
|||||||
};
|
};
|
||||||
const message: TwitchChatMessage = {
|
const message: TwitchChatMessage = {
|
||||||
...mockMessage,
|
...mockMessage,
|
||||||
|
message: "@testbot hello",
|
||||||
isOwner: false,
|
isOwner: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -154,6 +202,7 @@ describe("checkTwitchAccessControl", () => {
|
|||||||
};
|
};
|
||||||
const message: TwitchChatMessage = {
|
const message: TwitchChatMessage = {
|
||||||
...mockMessage,
|
...mockMessage,
|
||||||
|
message: "@testbot hello",
|
||||||
userId: "123456",
|
userId: "123456",
|
||||||
isMod: true,
|
isMod: true,
|
||||||
};
|
};
|
||||||
@ -175,6 +224,7 @@ describe("checkTwitchAccessControl", () => {
|
|||||||
};
|
};
|
||||||
const message: TwitchChatMessage = {
|
const message: TwitchChatMessage = {
|
||||||
...mockMessage,
|
...mockMessage,
|
||||||
|
message: "@testbot hello",
|
||||||
userId: "123456",
|
userId: "123456",
|
||||||
isMod: false,
|
isMod: false,
|
||||||
};
|
};
|
||||||
@ -197,6 +247,7 @@ describe("checkTwitchAccessControl", () => {
|
|||||||
};
|
};
|
||||||
const message: TwitchChatMessage = {
|
const message: TwitchChatMessage = {
|
||||||
...mockMessage,
|
...mockMessage,
|
||||||
|
message: "@testbot hello",
|
||||||
isMod: true,
|
isMod: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -216,6 +267,7 @@ describe("checkTwitchAccessControl", () => {
|
|||||||
};
|
};
|
||||||
const message: TwitchChatMessage = {
|
const message: TwitchChatMessage = {
|
||||||
...mockMessage,
|
...mockMessage,
|
||||||
|
message: "@testbot hello",
|
||||||
isVip: true,
|
isVip: true,
|
||||||
isMod: false,
|
isMod: false,
|
||||||
isSub: false,
|
isSub: false,
|
||||||
@ -236,6 +288,7 @@ describe("checkTwitchAccessControl", () => {
|
|||||||
};
|
};
|
||||||
const message: TwitchChatMessage = {
|
const message: TwitchChatMessage = {
|
||||||
...mockMessage,
|
...mockMessage,
|
||||||
|
message: "@testbot hello",
|
||||||
isMod: false,
|
isMod: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -253,9 +306,13 @@ describe("checkTwitchAccessControl", () => {
|
|||||||
...mockAccount,
|
...mockAccount,
|
||||||
allowedRoles: ["all"],
|
allowedRoles: ["all"],
|
||||||
};
|
};
|
||||||
|
const message: TwitchChatMessage = {
|
||||||
|
...mockMessage,
|
||||||
|
message: "@testbot hello",
|
||||||
|
};
|
||||||
|
|
||||||
const result = checkTwitchAccessControl({
|
const result = checkTwitchAccessControl({
|
||||||
message: mockMessage,
|
message,
|
||||||
account,
|
account,
|
||||||
botUsername: "testbot",
|
botUsername: "testbot",
|
||||||
});
|
});
|
||||||
@ -270,6 +327,7 @@ describe("checkTwitchAccessControl", () => {
|
|||||||
};
|
};
|
||||||
const message: TwitchChatMessage = {
|
const message: TwitchChatMessage = {
|
||||||
...mockMessage,
|
...mockMessage,
|
||||||
|
message: "@testbot hello",
|
||||||
isMod: true,
|
isMod: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -288,6 +346,7 @@ describe("checkTwitchAccessControl", () => {
|
|||||||
};
|
};
|
||||||
const message: TwitchChatMessage = {
|
const message: TwitchChatMessage = {
|
||||||
...mockMessage,
|
...mockMessage,
|
||||||
|
message: "@testbot hello",
|
||||||
isSub: true,
|
isSub: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -306,6 +365,7 @@ describe("checkTwitchAccessControl", () => {
|
|||||||
};
|
};
|
||||||
const message: TwitchChatMessage = {
|
const message: TwitchChatMessage = {
|
||||||
...mockMessage,
|
...mockMessage,
|
||||||
|
message: "@testbot hello",
|
||||||
isOwner: true,
|
isOwner: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -324,6 +384,7 @@ describe("checkTwitchAccessControl", () => {
|
|||||||
};
|
};
|
||||||
const message: TwitchChatMessage = {
|
const message: TwitchChatMessage = {
|
||||||
...mockMessage,
|
...mockMessage,
|
||||||
|
message: "@testbot hello",
|
||||||
isVip: true,
|
isVip: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -365,7 +426,8 @@ describe("checkTwitchAccessControl", () => {
|
|||||||
};
|
};
|
||||||
const message: TwitchChatMessage = {
|
const message: TwitchChatMessage = {
|
||||||
...mockMessage,
|
...mockMessage,
|
||||||
isOwner: false, // Not owner, but in allowlist
|
message: "@testbot hello",
|
||||||
|
isOwner: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
const result = checkTwitchAccessControl({
|
const result = checkTwitchAccessControl({
|
||||||
|
|||||||
@ -38,7 +38,7 @@ export function checkTwitchAccessControl(params: {
|
|||||||
}): TwitchAccessControlResult {
|
}): TwitchAccessControlResult {
|
||||||
const { message, account, botUsername } = params;
|
const { message, account, botUsername } = params;
|
||||||
|
|
||||||
if (account.requireMention) {
|
if (account.requireMention ?? true) {
|
||||||
const mentions = extractMentions(message.message);
|
const mentions = extractMentions(message.message);
|
||||||
if (!mentions.includes(botUsername.toLowerCase())) {
|
if (!mentions.includes(botUsername.toLowerCase())) {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -269,10 +269,9 @@ const dmPolicy: ChannelOnboardingDmPolicy = {
|
|||||||
return "disabled";
|
return "disabled";
|
||||||
},
|
},
|
||||||
setPolicy: (cfg, policy) => {
|
setPolicy: (cfg, policy) => {
|
||||||
// Map policy to Twitch roles
|
|
||||||
const allowedRoles: TwitchRole[] =
|
const allowedRoles: TwitchRole[] =
|
||||||
policy === "open" ? ["all"] : policy === "allowlist" ? [] : ["moderator"];
|
policy === "open" ? ["all"] : policy === "allowlist" ? [] : ["moderator"];
|
||||||
return setTwitchAccessControl(cfg as ClawdbotConfig, allowedRoles, false);
|
return setTwitchAccessControl(cfg as ClawdbotConfig, allowedRoles, true);
|
||||||
},
|
},
|
||||||
promptAllowFrom: async ({ cfg, prompter }) => {
|
promptAllowFrom: async ({ cfg, prompter }) => {
|
||||||
const account = getAccountConfig(cfg, DEFAULT_ACCOUNT_ID);
|
const account = getAccountConfig(cfg, DEFAULT_ACCOUNT_ID);
|
||||||
@ -378,12 +377,7 @@ export const twitchOnboardingAdapter: ChannelOnboardingAdapter = {
|
|||||||
? ["moderator", "vip"]
|
? ["moderator", "vip"]
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
const requireMention = accessConfig.policy === "open";
|
const cfgWithAccessControl = setTwitchAccessControl(cfgWithAllowFrom, allowedRoles, true);
|
||||||
const cfgWithAccessControl = setTwitchAccessControl(
|
|
||||||
cfgWithAllowFrom,
|
|
||||||
allowedRoles,
|
|
||||||
requireMention,
|
|
||||||
);
|
|
||||||
return { cfg: cfgWithAccessControl };
|
return { cfg: cfgWithAccessControl };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user