Skip to content

Commit 2e68a8d

Browse files
forgetsoclaude
andauthored
fix(provider): plumb TLS handshake timings into escalation + short-circuit sessions (#2803)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 8adb485 commit 2e68a8d

4 files changed

Lines changed: 42 additions & 1 deletion

File tree

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
"@prosopo/provider": patch
3+
---
4+
5+
fix(provider): persist TLS handshake timings on escalation + short-circuit sessions
6+
7+
`buildEscalation` (post-PoW image/puzzle escalation) and `runConfiguredCaptchaTypeShortCircuit` (sitekeys with a configured captchaType) both bypass `FrictionlessManager.setSessionParams`, so `req.tcpToChelloMs` / `req.chelloToHandshakeMs` were captured by the middleware but never landed on the resulting session record.
8+
9+
Threads the current request's per-connection timings through both paths:
10+
11+
- New optional `handshakeTiming` arg on `buildEscalation`, forwarded to `createSession`. Timings come from the current PoW-submit request, not from `originSession` (whose values belong to the earlier frictionless request's TCP connection).
12+
- New optional `tcpToChelloMs` / `chelloToHandshakeMs` on `ShortCircuitInput`, spread into the locally-built `sessionParams`.
13+
14+
The frictionless main path (`sendCaptcha` / `registerBlockedSession`) was already correct — it merges from `setSessionParams`, which the handler populates.

packages/provider/src/api/captcha/getFrictionlessCaptchaChallenge/handler.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,12 @@ export default (
388388
sessionMode,
389389
userSitekeyIpHash,
390390
logger: req.logger,
391+
...(req.tcpToChelloMs !== undefined && {
392+
tcpToChelloMs: req.tcpToChelloMs,
393+
}),
394+
...(req.chelloToHandshakeMs !== undefined && {
395+
chelloToHandshakeMs: req.chelloToHandshakeMs,
396+
}),
391397
},
392398
res,
393399
);

packages/provider/src/api/captcha/getFrictionlessCaptchaChallenge/shortCircuit.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ export type ShortCircuitInput = {
4040
sessionMode: ModeEnum | undefined;
4141
userSitekeyIpHash: string;
4242
logger: Logger;
43+
tcpToChelloMs?: number;
44+
chelloToHandshakeMs?: number;
4345
};
4446

4547
// Bypasses the bot-detection decision machine when the sitekey is configured
@@ -69,6 +71,12 @@ export const runConfiguredCaptchaTypeShortCircuit = async (
6971
headers: input.flatHeaders,
7072
mode: input.sessionMode,
7173
userSitekeyIpHash: input.userSitekeyIpHash,
74+
...(input.tcpToChelloMs !== undefined && {
75+
tcpToChelloMs: input.tcpToChelloMs,
76+
}),
77+
...(input.chelloToHandshakeMs !== undefined && {
78+
chelloToHandshakeMs: input.chelloToHandshakeMs,
79+
}),
7280
};
7381

7482
input.logger.info(() => ({

packages/provider/src/api/captcha/submitPoWCaptchaSolution.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,10 @@ export default (env: ProviderEnvironment) =>
187187
}));
188188
}
189189

190-
const escalation = await buildEscalation(tasks, result, challenge);
190+
const escalation = await buildEscalation(tasks, result, challenge, {
191+
tcpToChelloMs: req.tcpToChelloMs,
192+
chelloToHandshakeMs: req.chelloToHandshakeMs,
193+
});
191194
const response: PowCaptchaSolutionResponse = {
192195
status: "ok",
193196
// On escalation the user is not done — they still need to clear
@@ -229,6 +232,14 @@ export const buildEscalation = async (
229232
tasks: Tasks,
230233
result: { verified: boolean; routingOutput?: { captchaType: CaptchaType } },
231234
challenge: string,
235+
// TLS handshake timings are per-connection: they must come from the
236+
// current PoW-submit request, not from `originSession` (whose values
237+
// belong to a different TCP connection made during the earlier
238+
// frictionless request).
239+
handshakeTiming?: {
240+
tcpToChelloMs?: number;
241+
chelloToHandshakeMs?: number;
242+
},
232243
): Promise<PowCaptchaSolutionEscalation | undefined> => {
233244
if (!result.verified || !result.routingOutput) return undefined;
234245
const routedType = result.routingOutput.captchaType;
@@ -285,6 +296,8 @@ export const buildEscalation = async (
285296
originSession.entropyWallClockOffsetMs,
286297
originSession.entropyMathRandomFirst,
287298
originSession.currentUrl,
299+
handshakeTiming?.tcpToChelloMs,
300+
handshakeTiming?.chelloToHandshakeMs,
288301
);
289302

290303
// Record the origin → escalation sessionId mapping so a /captcha/*

0 commit comments

Comments
 (0)