security(zalo): scope pairing store by account
This commit is contained in:
committed by
Peter Steinberger
parent
c63c179278
commit
6b7d3fb011
@@ -47,13 +47,16 @@ function registerTarget(params: {
|
||||
path: string;
|
||||
secret?: string;
|
||||
statusSink?: (patch: { lastInboundAt?: number; lastOutboundAt?: number }) => void;
|
||||
account?: ResolvedZaloAccount;
|
||||
config?: OpenClawConfig;
|
||||
core?: PluginRuntime;
|
||||
}): () => void {
|
||||
return registerZaloWebhookTarget({
|
||||
token: "tok",
|
||||
account: DEFAULT_ACCOUNT,
|
||||
config: {} as OpenClawConfig,
|
||||
account: params.account ?? DEFAULT_ACCOUNT,
|
||||
config: params.config ?? ({} as OpenClawConfig),
|
||||
runtime: {},
|
||||
core: {} as PluginRuntime,
|
||||
core: params.core ?? ({} as PluginRuntime),
|
||||
secret: params.secret ?? "secret",
|
||||
path: params.path,
|
||||
mediaMaxMb: 5,
|
||||
@@ -61,6 +64,34 @@ function registerTarget(params: {
|
||||
});
|
||||
}
|
||||
|
||||
function createPairingAuthCore(params?: { storeAllowFrom?: string[]; pairingCreated?: boolean }): {
|
||||
core: PluginRuntime;
|
||||
readAllowFromStore: ReturnType<typeof vi.fn>;
|
||||
upsertPairingRequest: ReturnType<typeof vi.fn>;
|
||||
} {
|
||||
const readAllowFromStore = vi.fn().mockResolvedValue(params?.storeAllowFrom ?? []);
|
||||
const upsertPairingRequest = vi
|
||||
.fn()
|
||||
.mockResolvedValue({ code: "PAIRCODE", created: params?.pairingCreated ?? false });
|
||||
const core = {
|
||||
logging: {
|
||||
shouldLogVerbose: () => false,
|
||||
},
|
||||
channel: {
|
||||
pairing: {
|
||||
readAllowFromStore,
|
||||
upsertPairingRequest,
|
||||
buildPairingReply: vi.fn(() => "Pairing code: PAIRCODE"),
|
||||
},
|
||||
commands: {
|
||||
shouldComputeCommandAuthorized: vi.fn(() => false),
|
||||
resolveCommandAuthorizedFromAuthorizers: vi.fn(() => false),
|
||||
},
|
||||
},
|
||||
} as unknown as PluginRuntime;
|
||||
return { core, readAllowFromStore, upsertPairingRequest };
|
||||
}
|
||||
|
||||
describe("handleZaloWebhookRequest", () => {
|
||||
afterEach(() => {
|
||||
clearZaloWebhookSecurityStateForTest();
|
||||
@@ -206,7 +237,6 @@ describe("handleZaloWebhookRequest", () => {
|
||||
unregister();
|
||||
}
|
||||
});
|
||||
|
||||
it("does not grow status counters when query strings churn on unauthorized requests", async () => {
|
||||
const unregister = registerTarget({ path: "/hook-query-status" });
|
||||
|
||||
@@ -259,4 +289,60 @@ describe("handleZaloWebhookRequest", () => {
|
||||
unregister();
|
||||
}
|
||||
});
|
||||
|
||||
it("scopes DM pairing store reads and writes to accountId", async () => {
|
||||
const { core, readAllowFromStore, upsertPairingRequest } = createPairingAuthCore({
|
||||
pairingCreated: false,
|
||||
});
|
||||
const account: ResolvedZaloAccount = {
|
||||
...DEFAULT_ACCOUNT,
|
||||
accountId: "work",
|
||||
config: {
|
||||
dmPolicy: "pairing",
|
||||
allowFrom: [],
|
||||
},
|
||||
};
|
||||
const unregister = registerTarget({
|
||||
path: "/hook-account-scope",
|
||||
account,
|
||||
core,
|
||||
});
|
||||
|
||||
const payload = {
|
||||
event_name: "message.text.received",
|
||||
message: {
|
||||
from: { id: "123", name: "Attacker" },
|
||||
chat: { id: "dm-work", chat_type: "PRIVATE" },
|
||||
message_id: "msg-work-1",
|
||||
date: Math.floor(Date.now() / 1000),
|
||||
text: "hello",
|
||||
},
|
||||
};
|
||||
|
||||
try {
|
||||
await withServer(webhookRequestHandler, async (baseUrl) => {
|
||||
const response = await fetch(`${baseUrl}/hook-account-scope`, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"x-bot-api-secret-token": "secret",
|
||||
"content-type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
|
||||
expect(response.status).toBe(200);
|
||||
});
|
||||
} finally {
|
||||
unregister();
|
||||
}
|
||||
|
||||
expect(readAllowFromStore).toHaveBeenCalledWith("zalo", undefined, "work");
|
||||
expect(upsertPairingRequest).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
channel: "zalo",
|
||||
id: "123",
|
||||
accountId: "work",
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user