Spaces:
Configuration error
Configuration error
| import { afterEach, beforeEach, describe, expect, it } from "vitest"; | |
| import type { MoltbotConfig } from "../config/config.js"; | |
| import { setActivePluginRegistry } from "../plugins/runtime.js"; | |
| import { createTestRegistry } from "../test-utils/channel-plugins.js"; | |
| import { resolveCommandAuthorization } from "./command-auth.js"; | |
| import { hasControlCommand, hasInlineCommandTokens } from "./command-detection.js"; | |
| import { listChatCommands } from "./commands-registry.js"; | |
| import { parseActivationCommand } from "./group-activation.js"; | |
| import { parseSendPolicyCommand } from "./send-policy.js"; | |
| import type { MsgContext } from "./templating.js"; | |
| beforeEach(() => { | |
| setActivePluginRegistry(createTestRegistry([])); | |
| }); | |
| afterEach(() => { | |
| setActivePluginRegistry(createTestRegistry([])); | |
| }); | |
| describe("resolveCommandAuthorization", () => { | |
| it("falls back from empty SenderId to SenderE164", () => { | |
| const cfg = { | |
| channels: { whatsapp: { allowFrom: ["+123"] } }, | |
| } as MoltbotConfig; | |
| const ctx = { | |
| Provider: "whatsapp", | |
| Surface: "whatsapp", | |
| From: "whatsapp:+999", | |
| SenderId: "", | |
| SenderE164: "+123", | |
| } as MsgContext; | |
| const auth = resolveCommandAuthorization({ | |
| ctx, | |
| cfg, | |
| commandAuthorized: true, | |
| }); | |
| expect(auth.senderId).toBe("+123"); | |
| expect(auth.isAuthorizedSender).toBe(true); | |
| }); | |
| it("falls back from whitespace SenderId to SenderE164", () => { | |
| const cfg = { | |
| channels: { whatsapp: { allowFrom: ["+123"] } }, | |
| } as MoltbotConfig; | |
| const ctx = { | |
| Provider: "whatsapp", | |
| Surface: "whatsapp", | |
| From: "whatsapp:+999", | |
| SenderId: " ", | |
| SenderE164: "+123", | |
| } as MsgContext; | |
| const auth = resolveCommandAuthorization({ | |
| ctx, | |
| cfg, | |
| commandAuthorized: true, | |
| }); | |
| expect(auth.senderId).toBe("+123"); | |
| expect(auth.isAuthorizedSender).toBe(true); | |
| }); | |
| it("falls back to From when SenderId and SenderE164 are whitespace", () => { | |
| const cfg = { | |
| channels: { whatsapp: { allowFrom: ["+999"] } }, | |
| } as MoltbotConfig; | |
| const ctx = { | |
| Provider: "whatsapp", | |
| Surface: "whatsapp", | |
| From: "whatsapp:+999", | |
| SenderId: " ", | |
| SenderE164: " ", | |
| } as MsgContext; | |
| const auth = resolveCommandAuthorization({ | |
| ctx, | |
| cfg, | |
| commandAuthorized: true, | |
| }); | |
| expect(auth.senderId).toBe("+999"); | |
| expect(auth.isAuthorizedSender).toBe(true); | |
| }); | |
| it("falls back from un-normalizable SenderId to SenderE164", () => { | |
| const cfg = { | |
| channels: { whatsapp: { allowFrom: ["+123"] } }, | |
| } as MoltbotConfig; | |
| const ctx = { | |
| Provider: "whatsapp", | |
| Surface: "whatsapp", | |
| From: "whatsapp:+999", | |
| SenderId: "wat", | |
| SenderE164: "+123", | |
| } as MsgContext; | |
| const auth = resolveCommandAuthorization({ | |
| ctx, | |
| cfg, | |
| commandAuthorized: true, | |
| }); | |
| expect(auth.senderId).toBe("+123"); | |
| expect(auth.isAuthorizedSender).toBe(true); | |
| }); | |
| it("prefers SenderE164 when SenderId does not match allowFrom", () => { | |
| const cfg = { | |
| channels: { whatsapp: { allowFrom: ["+41796666864"] } }, | |
| } as MoltbotConfig; | |
| const ctx = { | |
| Provider: "whatsapp", | |
| Surface: "whatsapp", | |
| From: "whatsapp:120363401234567890@g.us", | |
| SenderId: "123@lid", | |
| SenderE164: "+41796666864", | |
| } as MsgContext; | |
| const auth = resolveCommandAuthorization({ | |
| ctx, | |
| cfg, | |
| commandAuthorized: true, | |
| }); | |
| expect(auth.senderId).toBe("+41796666864"); | |
| expect(auth.isAuthorizedSender).toBe(true); | |
| }); | |
| }); | |
| describe("control command parsing", () => { | |
| it("requires slash for send policy", () => { | |
| expect(parseSendPolicyCommand("/send on")).toEqual({ | |
| hasCommand: true, | |
| mode: "allow", | |
| }); | |
| expect(parseSendPolicyCommand("/send: on")).toEqual({ | |
| hasCommand: true, | |
| mode: "allow", | |
| }); | |
| expect(parseSendPolicyCommand("/send")).toEqual({ hasCommand: true }); | |
| expect(parseSendPolicyCommand("/send:")).toEqual({ hasCommand: true }); | |
| expect(parseSendPolicyCommand("send on")).toEqual({ hasCommand: false }); | |
| expect(parseSendPolicyCommand("send")).toEqual({ hasCommand: false }); | |
| }); | |
| it("requires slash for activation", () => { | |
| expect(parseActivationCommand("/activation mention")).toEqual({ | |
| hasCommand: true, | |
| mode: "mention", | |
| }); | |
| expect(parseActivationCommand("/activation: mention")).toEqual({ | |
| hasCommand: true, | |
| mode: "mention", | |
| }); | |
| expect(parseActivationCommand("/activation:")).toEqual({ | |
| hasCommand: true, | |
| }); | |
| expect(parseActivationCommand("activation mention")).toEqual({ | |
| hasCommand: false, | |
| }); | |
| }); | |
| it("treats bare commands as non-control", () => { | |
| expect(hasControlCommand("send")).toBe(false); | |
| expect(hasControlCommand("help")).toBe(false); | |
| expect(hasControlCommand("/commands")).toBe(true); | |
| expect(hasControlCommand("/commands:")).toBe(true); | |
| expect(hasControlCommand("commands")).toBe(false); | |
| expect(hasControlCommand("/status")).toBe(true); | |
| expect(hasControlCommand("/status:")).toBe(true); | |
| expect(hasControlCommand("status")).toBe(false); | |
| expect(hasControlCommand("usage")).toBe(false); | |
| for (const command of listChatCommands()) { | |
| for (const alias of command.textAliases) { | |
| expect(hasControlCommand(alias)).toBe(true); | |
| expect(hasControlCommand(`${alias}:`)).toBe(true); | |
| } | |
| } | |
| expect(hasControlCommand("/compact")).toBe(true); | |
| expect(hasControlCommand("/compact:")).toBe(true); | |
| expect(hasControlCommand("compact")).toBe(false); | |
| }); | |
| it("respects disabled config/debug commands", () => { | |
| const cfg = { commands: { config: false, debug: false } }; | |
| expect(hasControlCommand("/config show", cfg)).toBe(false); | |
| expect(hasControlCommand("/debug show", cfg)).toBe(false); | |
| }); | |
| it("requires commands to be the full message", () => { | |
| expect(hasControlCommand("hello /status")).toBe(false); | |
| expect(hasControlCommand("/status please")).toBe(false); | |
| expect(hasControlCommand("prefix /send on")).toBe(false); | |
| expect(hasControlCommand("/send on")).toBe(true); | |
| }); | |
| it("detects inline command tokens", () => { | |
| expect(hasInlineCommandTokens("hello /status")).toBe(true); | |
| expect(hasInlineCommandTokens("hey /think high")).toBe(true); | |
| expect(hasInlineCommandTokens("plain text")).toBe(false); | |
| expect(hasInlineCommandTokens("http://example.com/path")).toBe(false); | |
| expect(hasInlineCommandTokens("stop")).toBe(false); | |
| }); | |
| it("ignores telegram commands addressed to other bots", () => { | |
| expect( | |
| hasControlCommand("/help@otherbot", undefined, { | |
| botUsername: "moltbot", | |
| }), | |
| ).toBe(false); | |
| expect( | |
| hasControlCommand("/help@moltbot", undefined, { | |
| botUsername: "moltbot", | |
| }), | |
| ).toBe(true); | |
| }); | |
| }); | |