|
1 | 1 | import { beforeEach, describe, expect, it, vi } from "vitest"; |
2 | 2 | |
3 | | -const resolvePinnedHostnameWithPolicyMock = vi.fn(); |
| 3 | +const { resolvePinnedHostnameWithPolicyMock } = vi.hoisted(() => ({ |
| 4 | +resolvePinnedHostnameWithPolicyMock: vi.fn(), |
| 5 | +})); |
4 | 6 | |
5 | 7 | vi.mock("openclaw/plugin-sdk/ssrf-runtime", () => ({ |
6 | 8 | resolvePinnedHostnameWithPolicy: (...args: unknown[]) => |
@@ -9,6 +11,8 @@ vi.mock("openclaw/plugin-sdk/ssrf-runtime", () => ({
|
9 | 11 | |
10 | 12 | import { deleteWebhook, getWebhookInfo, sendChatAction, sendPhoto, type ZaloFetch } from "./api.js"; |
11 | 13 | |
| 14 | +const MAX_TIMER_TIMEOUT_MS = 2_147_000_000; |
| 15 | + |
12 | 16 | function createOkFetcher() { |
13 | 17 | return vi.fn<ZaloFetch>(async () => new Response(JSON.stringify({ ok: true, result: {} }))); |
14 | 18 | } |
@@ -90,6 +94,38 @@ describe("Zalo API request methods", () => {
|
90 | 94 | } |
91 | 95 | }); |
92 | 96 | |
| 97 | +it("caps oversized sendChatAction timeouts before scheduling the timer", async () => { |
| 98 | +const setTimeoutMock = vi |
| 99 | +.spyOn(globalThis, "setTimeout") |
| 100 | +.mockImplementation((() => 1) as typeof setTimeout); |
| 101 | +const clearTimeoutMock = vi |
| 102 | +.spyOn(globalThis, "clearTimeout") |
| 103 | +.mockImplementation(() => undefined); |
| 104 | +try { |
| 105 | +const fetcher = vi.fn<ZaloFetch>( |
| 106 | +async () => |
| 107 | +({ |
| 108 | +json: async () => ({ ok: true, result: {} }), |
| 109 | +}) as Response, |
| 110 | +); |
| 111 | + |
| 112 | +await sendChatAction( |
| 113 | +"test-token", |
| 114 | +{ |
| 115 | +chat_id: "chat-123", |
| 116 | +action: "typing", |
| 117 | +}, |
| 118 | +fetcher, |
| 119 | +MAX_TIMER_TIMEOUT_MS + 1_000_000, |
| 120 | +); |
| 121 | + |
| 122 | +expect(setTimeoutMock).toHaveBeenCalledWith(expect.any(Function), MAX_TIMER_TIMEOUT_MS); |
| 123 | +} finally { |
| 124 | +setTimeoutMock.mockRestore(); |
| 125 | +clearTimeoutMock.mockRestore(); |
| 126 | +} |
| 127 | +}); |
| 128 | + |
93 | 129 | it("validates outbound photo URLs against the SSRF guard before posting", async () => { |
94 | 130 | const fetcher = createOkFetcher(); |
95 | 131 | |
|