mirror of
https://fastgit.cc/github.com/openclaw/openclaw
synced 2026-04-30 14:02:56 +08:00
fix(commands): validate channel auth override
This commit is contained in:
@@ -55,7 +55,11 @@ export function resolveEffectiveCommandAuthorized(params: {
|
||||
commandAuthorized: boolean;
|
||||
channelResolvedCommandAuthorization?: ChannelResolvedCommandAuthorization;
|
||||
}): boolean {
|
||||
return params.channelResolvedCommandAuthorization?.isAuthorizedSender ?? params.commandAuthorized;
|
||||
const provided = resolveProvidedChannelCommandAuthorization({
|
||||
channelResolvedCommandAuthorization: params.channelResolvedCommandAuthorization,
|
||||
warnOnMalformed: false,
|
||||
});
|
||||
return provided?.isAuthorizedSender ?? params.commandAuthorized;
|
||||
}
|
||||
|
||||
export function resolveCommandProviderIdFromContext(params: {
|
||||
@@ -67,21 +71,27 @@ export function resolveCommandProviderIdFromContext(params: {
|
||||
|
||||
function resolveProvidedChannelCommandAuthorization(params: {
|
||||
channelResolvedCommandAuthorization?: ChannelResolvedCommandAuthorization;
|
||||
warnOnMalformed?: boolean;
|
||||
}): ChannelResolvedCommandAuthorization | undefined {
|
||||
const { channelResolvedCommandAuthorization: provided } = params;
|
||||
const maybeWarn = (reason: string) => {
|
||||
if (params.warnOnMalformed !== false) {
|
||||
warnMalformedChannelResolvedCommandAuthorization(reason);
|
||||
}
|
||||
};
|
||||
if (!provided || typeof provided !== "object") {
|
||||
return undefined;
|
||||
}
|
||||
if (!Array.isArray(provided.ownerList)) {
|
||||
warnMalformedChannelResolvedCommandAuthorization("ownerList must be an array");
|
||||
maybeWarn("ownerList must be an array");
|
||||
return undefined;
|
||||
}
|
||||
if (typeof provided.senderIsOwner !== "boolean") {
|
||||
warnMalformedChannelResolvedCommandAuthorization("senderIsOwner must be a boolean");
|
||||
maybeWarn("senderIsOwner must be a boolean");
|
||||
return undefined;
|
||||
}
|
||||
if (typeof provided.isAuthorizedSender !== "boolean") {
|
||||
warnMalformedChannelResolvedCommandAuthorization("isAuthorizedSender must be a boolean");
|
||||
maybeWarn("isAuthorizedSender must be a boolean");
|
||||
return undefined;
|
||||
}
|
||||
return {
|
||||
|
||||
@@ -1505,6 +1505,68 @@ describe("dispatchReplyFromConfig", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("does not trust malformed channel auth for plugin inbound-claim events", async () => {
|
||||
setNoAbort();
|
||||
hookMocks.runner.runInboundClaimForPluginOutcome.mockResolvedValue({
|
||||
status: "handled",
|
||||
result: { handled: true },
|
||||
});
|
||||
sessionBindingMocks.resolveByConversation.mockReturnValue({
|
||||
bindingId: "binding-auth-invalid-1",
|
||||
targetSessionKey: "plugin-binding:codex:auth-invalid-1",
|
||||
targetKind: "session",
|
||||
conversation: {
|
||||
channel: "telegram",
|
||||
accountId: "default",
|
||||
conversationId: "chat:trusted",
|
||||
},
|
||||
status: "active",
|
||||
boundAt: 1710000000000,
|
||||
metadata: {
|
||||
pluginBindingOwner: "plugin",
|
||||
pluginId: "openclaw-codex-app-server",
|
||||
},
|
||||
} satisfies SessionBindingRecord);
|
||||
const dispatcher = createDispatcher();
|
||||
const ctx = buildTestCtx({
|
||||
Provider: "telegram",
|
||||
Surface: "telegram",
|
||||
OriginatingChannel: "telegram",
|
||||
OriginatingTo: "telegram:chat:trusted",
|
||||
To: "telegram:chat:trusted",
|
||||
AccountId: "default",
|
||||
SenderId: "trusted-user",
|
||||
CommandAuthorized: false,
|
||||
WasMentioned: false,
|
||||
CommandBody: "/status",
|
||||
RawBody: "/status",
|
||||
Body: "/status",
|
||||
MessageSid: "msg-claim-auth-invalid-1",
|
||||
SessionKey: "agent:main:telegram:chat:trusted",
|
||||
});
|
||||
const channelResolvedCommandAuthorization = {
|
||||
ownerList: "trusted-user",
|
||||
senderIsOwner: true,
|
||||
isAuthorizedSender: true,
|
||||
} as unknown as ChannelResolvedCommandAuthorization;
|
||||
|
||||
await dispatchReplyFromConfig({
|
||||
ctx,
|
||||
cfg: emptyConfig,
|
||||
dispatcher,
|
||||
replyResolver: vi.fn(async () => ({ text: "unused" }) as ReplyPayload),
|
||||
replyOptions: { channelResolvedCommandAuthorization },
|
||||
});
|
||||
|
||||
expect(hookMocks.runner.runInboundClaimForPluginOutcome).toHaveBeenCalledWith(
|
||||
"openclaw-codex-app-server",
|
||||
expect.objectContaining({
|
||||
commandAuthorized: false,
|
||||
}),
|
||||
expect.anything(),
|
||||
);
|
||||
});
|
||||
|
||||
it("routes ACP sessions through the runtime branch and streams block replies", async () => {
|
||||
setNoAbort();
|
||||
const runtime = createAcpRuntime([
|
||||
|
||||
Reference in New Issue
Block a user