From 1d3f9e4038948e78347c2a5b395583b899995be2 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Tim=20D=C3=BCsterhus?= Date: Mon, 26 Jul 2021 14:42:44 +0200 Subject: [PATCH] Delete the captcha registration after retrieving data in Comment/Add and Message/Reply When a validation error is encountered, a new template with a new captcha will be sent. However the logic within the captcha controller prevents a callback from being added for a specific captcha ID if one is already registered. This leads to the previous captcha callback being reused for another attempt. This does not work, because a single instance of reCAPTCHA may only be used once, thus erroring out if the callback is invoked a second time. Fix this issue by deleting the captcha callback once we used it once. Upon another failure another template will be sent, re-registering a new and valid captcha. It was also considered caching the return value, however this will cause issues if the user mistypes a captcha as they will be unable to correct the error, due to the same value being returned on the next attempt. Ideally the `getData()` function would automatically delete the callback, making it a single-use callback by design. This might break API users relying on this current (broken) behavior, though. The whole (AJAX) CAPTCHA API looks broken beyond repair. It also relies on the jQuery parts being available. It should be cleanly refactored in a future version. --- ts/WoltLabSuite/Core/Ui/Comment/Add.ts | 6 ++++-- ts/WoltLabSuite/Core/Ui/Message/Reply.ts | 1 + .../install/files/js/WoltLabSuite/Core/Ui/Comment/Add.js | 6 ++++-- .../install/files/js/WoltLabSuite/Core/Ui/Message/Reply.js | 1 + 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/ts/WoltLabSuite/Core/Ui/Comment/Add.ts b/ts/WoltLabSuite/Core/Ui/Comment/Add.ts index 67c1049566..3018446c0f 100644 --- a/ts/WoltLabSuite/Core/Ui/Comment/Add.ts +++ b/ts/WoltLabSuite/Core/Ui/Comment/Add.ts @@ -99,8 +99,10 @@ class UiCommentAdd { }, }; - if (ControllerCaptcha.has("commentAdd")) { - const data = ControllerCaptcha.getData("commentAdd"); + const captchaId = "commentAdd"; + if (ControllerCaptcha.has(captchaId)) { + const data = ControllerCaptcha.getData(captchaId); + ControllerCaptcha.delete(captchaId); if (data instanceof Promise) { void data.then((data) => { parameters = Core.extend(parameters, data) as ArbitraryObject; diff --git a/ts/WoltLabSuite/Core/Ui/Message/Reply.ts b/ts/WoltLabSuite/Core/Ui/Message/Reply.ts index 4f8ed94003..9d10931f36 100644 --- a/ts/WoltLabSuite/Core/Ui/Message/Reply.ts +++ b/ts/WoltLabSuite/Core/Ui/Message/Reply.ts @@ -119,6 +119,7 @@ class UiMessageReply { const captchaId = target.dataset.captchaId!; if (ControllerCaptcha.has(captchaId)) { const data = ControllerCaptcha.getData(captchaId); + ControllerCaptcha.delete(captchaId); if (data instanceof Promise) { void data.then((data) => { parameters = Core.extend(parameters, data) as ArbitraryObject; diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Comment/Add.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Comment/Add.js index 31a67f4b05..b7bfafc9d3 100644 --- a/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Comment/Add.js +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Comment/Add.js @@ -76,8 +76,10 @@ define(["require", "exports", "tslib", "../../Ajax", "../../Controller/Captcha", }, }, }; - if (Captcha_1.default.has("commentAdd")) { - const data = Captcha_1.default.getData("commentAdd"); + const captchaId = "commentAdd"; + if (Captcha_1.default.has(captchaId)) { + const data = Captcha_1.default.getData(captchaId); + Captcha_1.default.delete(captchaId); if (data instanceof Promise) { void data.then((data) => { parameters = Core.extend(parameters, data); diff --git a/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Message/Reply.js b/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Message/Reply.js index ae6e5115ee..5f3fc97ab8 100644 --- a/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Message/Reply.js +++ b/wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Message/Reply.js @@ -80,6 +80,7 @@ define(["require", "exports", "tslib", "../../Ajax", "../../Core", "../../Event/ const captchaId = target.dataset.captchaId; if (Captcha_1.default.has(captchaId)) { const data = Captcha_1.default.getData(captchaId); + Captcha_1.default.delete(captchaId); if (data instanceof Promise) { void data.then((data) => { parameters = Core.extend(parameters, data); -- 2.20.1