aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authoramankumarsingh77 <amankumarsingh7702@gmal.com>2026-05-02 15:48:28 +0530
committeramankumarsingh77 <amankumarsingh7702@gmal.com>2026-05-02 15:48:28 +0530
commit52fd9523d1e4739d9a9e082e11686f244c767cc1 (patch)
tree8277f0c8628bf9890cf3548ff51962e6b5940337 /src
parent22019a655c8708d5253e1d25b8ae654069032666 (diff)
fix(cdp): validate inbound CDP messages with a runtime type guard
Diffstat (limited to 'src')
-rw-r--r--src/cdp/transport.ts12
-rw-r--r--src/cdp/types.ts21
2 files changed, 31 insertions, 2 deletions
diff --git a/src/cdp/transport.ts b/src/cdp/transport.ts
index 154df48..6da25fa 100644
--- a/src/cdp/transport.ts
+++ b/src/cdp/transport.ts
@@ -1,6 +1,7 @@
import WebSocket from "ws";
import { type Result, err, ok } from "../util/result";
import { type CdpError, cdpError } from "./errors";
+import { isCdpRawMessage } from "./types";
import type { CdpEvent, CdpRawMessage } from "./types";
const DEFAULT_TIMEOUT_MS = 15_000;
@@ -75,12 +76,14 @@ export const createCdpTransport = (): CdpTransport => {
let queue = makeEventQueue();
const handleMessage = (raw: string): void => {
- let msg: CdpRawMessage;
+ let parsed: unknown;
try {
- msg = JSON.parse(raw);
+ parsed = JSON.parse(raw);
} catch {
return;
}
+ if (!isCdpRawMessage(parsed)) return;
+ const msg: CdpRawMessage = parsed;
if (msg.id === undefined) {
if (msg.method) {
queue.push({
@@ -194,6 +197,11 @@ export const createCdpTransport = (): CdpTransport => {
});
},
events(): AsyncIterable<CdpEvent> {
+ // Single-consumer: each connection's event stream may be iterated by
+ // exactly one for-await loop. Calling events() multiple times returns
+ // the same iterable; the second consumer will silently steal events
+ // from the first. After a reconnect, the previous iterator is ended
+ // and callers must re-call events() to receive new events.
return queue.iter;
},
state(): "open" | "closed" | "connecting" {
diff --git a/src/cdp/types.ts b/src/cdp/types.ts
index cbcb2d5..2bcc352 100644
--- a/src/cdp/types.ts
+++ b/src/cdp/types.ts
@@ -49,3 +49,24 @@ const INTERNAL_PREFIXES: ReadonlyArray<string> = [
export const isInternalUrl = (url: string): boolean =>
INTERNAL_PREFIXES.some((p) => url.startsWith(p));
+
+const isObject = (v: unknown): v is Readonly<Record<string, unknown>> =>
+ typeof v === "object" && v !== null && !Array.isArray(v);
+
+export const isCdpRawMessage = (v: unknown): v is CdpRawMessage => {
+ if (!isObject(v)) return false;
+ const id = v["id"];
+ if (id !== undefined && typeof id !== "number") return false;
+ const method = v["method"];
+ if (method !== undefined && typeof method !== "string") return false;
+ const sessionId = v["sessionId"];
+ if (sessionId !== undefined && typeof sessionId !== "string") return false;
+ const errVal = v["error"];
+ if (errVal !== undefined) {
+ if (!isObject(errVal)) return false;
+ if (typeof errVal["message"] !== "string") return false;
+ const code = errVal["code"];
+ if (code !== undefined && typeof code !== "number") return false;
+ }
+ return true;
+};