mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-26 17:32:16 +00:00
fix: blcok non-owner authorized senders from chaning /send policy (#53994)
This commit is contained in:
@@ -18,6 +18,7 @@ import {
|
||||
isTelegramSurface,
|
||||
resolveChannelAccountId,
|
||||
} from "./channel-context.js";
|
||||
import { rejectNonOwnerCommand, rejectUnauthorizedCommand } from "./command-gates.js";
|
||||
import { handleAbortTrigger, handleStopCommand } from "./commands-session-abort.js";
|
||||
import { persistSessionEntry } from "./commands-session-store.js";
|
||||
import type { CommandHandler } from "./commands-types.js";
|
||||
@@ -217,11 +218,13 @@ export const handleSendPolicyCommand: CommandHandler = async (params, allowTextC
|
||||
if (!sendPolicyCommand.hasCommand) {
|
||||
return null;
|
||||
}
|
||||
if (!params.command.isAuthorizedSender) {
|
||||
logVerbose(
|
||||
`Ignoring /send from unauthorized sender: ${params.command.senderId || "<unknown>"}`,
|
||||
);
|
||||
return { shouldContinue: false };
|
||||
const unauthorizedResult = rejectUnauthorizedCommand(params, "/send");
|
||||
if (unauthorizedResult) {
|
||||
return unauthorizedResult;
|
||||
}
|
||||
const nonOwnerResult = rejectNonOwnerCommand(params, "/send");
|
||||
if (nonOwnerResult) {
|
||||
return nonOwnerResult;
|
||||
}
|
||||
if (!sendPolicyCommand.mode) {
|
||||
return {
|
||||
|
||||
@@ -867,6 +867,101 @@ describe("handleCommands owner gating for privileged show commands", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("handleCommands /send owner gating", () => {
|
||||
it("blocks authorized non-owner senders from mutating session send policy", async () => {
|
||||
const params = buildParams("/send off", {
|
||||
commands: { text: true },
|
||||
channels: { whatsapp: { allowFrom: ["*"] } },
|
||||
} as OpenClawConfig);
|
||||
params.command.senderIsOwner = false;
|
||||
|
||||
const sessionEntry: SessionEntry = {
|
||||
sessionId: "session-send-policy",
|
||||
updatedAt: Date.now(),
|
||||
sendPolicy: "allow",
|
||||
};
|
||||
const sessionStore: Record<string, SessionEntry> = {
|
||||
[params.sessionKey]: sessionEntry,
|
||||
};
|
||||
|
||||
const result = await handleCommands({
|
||||
...params,
|
||||
sessionEntry,
|
||||
sessionStore,
|
||||
});
|
||||
|
||||
expect(result).toEqual({ shouldContinue: false });
|
||||
expect(sessionEntry.sendPolicy).toBe("allow");
|
||||
expect(sessionStore[params.sessionKey]?.sendPolicy).toBe("allow");
|
||||
});
|
||||
|
||||
it("allows owners to mutate session send policy", async () => {
|
||||
const params = buildParams("/send off", {
|
||||
commands: { text: true },
|
||||
channels: { whatsapp: { allowFrom: ["*"] } },
|
||||
} as OpenClawConfig);
|
||||
params.command.senderIsOwner = true;
|
||||
|
||||
const sessionEntry: SessionEntry = {
|
||||
sessionId: "session-send-policy-owner",
|
||||
updatedAt: Date.now(),
|
||||
sendPolicy: "allow",
|
||||
};
|
||||
const sessionStore: Record<string, SessionEntry> = {
|
||||
[params.sessionKey]: sessionEntry,
|
||||
};
|
||||
|
||||
const result = await handleCommands({
|
||||
...params,
|
||||
sessionEntry,
|
||||
sessionStore,
|
||||
});
|
||||
|
||||
expect(result.shouldContinue).toBe(false);
|
||||
expect(result.reply?.text).toContain("Send policy set to off");
|
||||
expect(sessionEntry.sendPolicy).toBe("deny");
|
||||
expect(sessionStore[params.sessionKey]?.sendPolicy).toBe("deny");
|
||||
});
|
||||
|
||||
it("returns an explicit unauthorized reply for native /send from non-owners", async () => {
|
||||
const params = buildParams(
|
||||
"/send off",
|
||||
{
|
||||
commands: { text: true },
|
||||
channels: { discord: { dm: { enabled: true, policy: "open" } } },
|
||||
} as OpenClawConfig,
|
||||
{
|
||||
Provider: "discord",
|
||||
Surface: "discord",
|
||||
CommandSource: "native",
|
||||
},
|
||||
);
|
||||
params.command.senderIsOwner = false;
|
||||
|
||||
const sessionEntry: SessionEntry = {
|
||||
sessionId: "session-send-policy-native",
|
||||
updatedAt: Date.now(),
|
||||
sendPolicy: "allow",
|
||||
};
|
||||
const sessionStore: Record<string, SessionEntry> = {
|
||||
[params.sessionKey]: sessionEntry,
|
||||
};
|
||||
|
||||
const result = await handleCommands({
|
||||
...params,
|
||||
sessionEntry,
|
||||
sessionStore,
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
shouldContinue: false,
|
||||
reply: { text: "You are not authorized to use this command." },
|
||||
});
|
||||
expect(sessionEntry.sendPolicy).toBe("allow");
|
||||
expect(sessionStore[params.sessionKey]?.sendPolicy).toBe("allow");
|
||||
});
|
||||
});
|
||||
|
||||
describe("handleCommands /config configWrites gating", () => {
|
||||
it("blocks disallowed /config set writes", async () => {
|
||||
const cases = [
|
||||
|
||||
Reference in New Issue
Block a user