@@ -9,6 +9,28 @@ import {
|
9 | 9 | } from "./probe.js"; |
10 | 10 | import { jsonResponse } from "./test-http-helpers.js"; |
11 | 11 | |
| 12 | +const DISCORD_PROBE_JSON_CAP_BYTES = 16 * 1024 * 1024; |
| 13 | + |
| 14 | +function oversizedDiscordProbeJsonResponse(onCancel: () => void): Response { |
| 15 | +const response = new Response( |
| 16 | +new ReadableStream<Uint8Array>({ |
| 17 | +start(controller) { |
| 18 | +controller.enqueue(new Uint8Array(DISCORD_PROBE_JSON_CAP_BYTES + 1)); |
| 19 | +}, |
| 20 | +cancel() { |
| 21 | +onCancel(); |
| 22 | +}, |
| 23 | +}), |
| 24 | +{ headers: { "content-type": "application/json" }, status: 200 }, |
| 25 | +); |
| 26 | +Object.defineProperty(response, "json", { |
| 27 | +value: async () => { |
| 28 | +throw new Error("unbounded json reader was used"); |
| 29 | +}, |
| 30 | +}); |
| 31 | +return response; |
| 32 | +} |
| 33 | + |
12 | 34 | describe("resolveDiscordPrivilegedIntentsFromFlags", () => { |
13 | 35 | beforeEach(() => { |
14 | 36 | vi.useRealTimers(); |
@@ -104,6 +126,21 @@ describe("resolveDiscordPrivilegedIntentsFromFlags", () => {
|
104 | 126 | expect(cancel).toHaveBeenCalledTimes(1); |
105 | 127 | }); |
106 | 128 | |
| 129 | +it("bounds oversized getMe probe JSON responses and cancels the stream", async () => { |
| 130 | +let cancelCount = 0; |
| 131 | +const fetcher = withFetchPreconnect(async () => |
| 132 | +oversizedDiscordProbeJsonResponse(() => { |
| 133 | +cancelCount += 1; |
| 134 | +}), |
| 135 | +); |
| 136 | + |
| 137 | +await expect(probeDiscord("MTIz.abc.def", 1_000, { fetcher })).resolves.toMatchObject({ |
| 138 | +ok: false, |
| 139 | +error: expect.stringContaining("discord.probe.getMe: JSON response exceeds 16777216 bytes"), |
| 140 | +}); |
| 141 | +expect(cancelCount).toBe(1); |
| 142 | +}); |
| 143 | + |
107 | 144 | it("derives application id from parseable tokens before probing REST", async () => { |
108 | 145 | let calls = 0; |
109 | 146 | const fetcher = withFetchPreconnect(async () => { |
|