Skip to content

Commit b764b8d

Browse files
simplify: remove captcha timeout in favour of hCaptcha callbacks
hCaptcha already fires error-callback and expired-callback in all failure cases, so the manual setTimeout was redundant complexity. Removing it simplifies getCaptchaToken() and avoids the arbitrary timeout value debate.
1 parent 5aa11e8 commit b764b8d

1 file changed

Lines changed: 3 additions & 24 deletions

File tree

EssentialCSharp.Web/wwwroot/js/chat-module.js

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ let captchaTokenResolve = null;
2020
let captchaTokenReject = null;
2121
let captchaPending = false; // prevents concurrent token requests overwriting promise callbacks
2222
let captchaRequestGeneration = 0;
23-
const CAPTCHA_TIMEOUT_MS = 90_000;
2423

2524
// Resolves once the widget has rendered. getCaptchaToken() awaits this so a user who
2625
// submits before hCaptcha finishes loading waits (up to 15 s) rather than getting a 403.
@@ -68,8 +67,7 @@ function initCaptchaWidget() {
6867
* Returns a fresh hCaptcha token, or null if captcha is not configured.
6968
* Waits for the widget to finish rendering if it has not yet (handles slow script loads).
7069
* Rejects with 'captcha-concurrent' if a token request is already in-flight.
71-
* Rejects with 'captcha-timeout' if the challenge does not complete within 90 seconds
72-
* after the widget is ready (the timer starts after widget load, not before).
70+
* Rejects with 'captcha-expired' or 'captcha-error' via hCaptcha's own callbacks.
7371
*/
7472
function getCaptchaToken() {
7573
if (!captchaSiteKey) return Promise.resolve(null);
@@ -79,42 +77,23 @@ function getCaptchaToken() {
7977

8078
// Chain onto captchaWidgetReady so calls made before the widget finishes loading
8179
// wait rather than immediately returning null and causing a 403.
82-
// The challenge timeout starts only after the widget is ready so script-load time
83-
// does not eat into the window available for completing an interactive challenge.
8480
return captchaWidgetReady.then(() => {
8581
if (requestGeneration !== captchaRequestGeneration) {
8682
captchaPending = false;
8783
return Promise.reject(new Error('captcha-stale'));
8884
}
8985

90-
let timeoutId;
91-
92-
const tokenPromise = new Promise((resolve, reject) => {
86+
return new Promise((resolve, reject) => {
9387
captchaTokenResolve = (token) => {
9488
captchaPending = false;
95-
clearTimeout(timeoutId); // cancel lingering timer so it can't corrupt the next call
9689
resolve(token);
9790
};
98-
captchaTokenReject = (err) => {
91+
captchaTokenReject = (err) => {
9992
captchaPending = false;
100-
clearTimeout(timeoutId);
10193
reject(err);
10294
};
10395
window.hcaptcha.execute(captchaWidgetId);
10496
});
105-
106-
const timeoutPromise = new Promise((_, reject) => {
107-
timeoutId = setTimeout(() => {
108-
if (requestGeneration !== captchaRequestGeneration) return;
109-
captchaRequestGeneration++;
110-
captchaPending = false;
111-
captchaTokenResolve = null;
112-
captchaTokenReject = null;
113-
reject(new Error('captcha-timeout'));
114-
}, CAPTCHA_TIMEOUT_MS);
115-
});
116-
117-
return Promise.race([tokenPromise, timeoutPromise]);
11897
});
11998
}
12099

0 commit comments

Comments
 (0)