Fix mCaptcha broken after Vite migration (#37492)

After the Webpack-to-Vite migration (#37002), mCaptcha stopped working
entirely on the registration page, throwing an error:

`TypeError: setting getter-only property "INPUT_NAME"`

This fix stops trying to mutate the read-only INPUT_NAME export. Instead
it probes for the Widget constructor at module.default (direct) or
module.default.default (CJS-wrapped), constructs the widget, and then
renames the hidden input element it creates to m-captcha-response which
is the field name Gitea's backend reads from the submitted form.

Generative AI was used to help with making this PR.

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: wxiaoguang <wxiaoguang@gmail.com>
Co-authored-by: Giteabot <teabot@gitea.io>
This commit is contained in:
rootful
2026-05-02 17:21:56 +02:00
committed by GitHub
parent 6b8dd90dc7
commit 3d838ef96a
6 changed files with 20 additions and 29 deletions
+1 -1
View File
@@ -26,7 +26,7 @@
"@github/paste-markdown": "1.5.3",
"@github/text-expander-element": "2.9.4",
"@lezer/highlight": "1.2.3",
"@mcaptcha/vanilla-glue": "0.1.0-alpha-3",
"@mcaptcha/vanilla-glue": "0.1.0-rc2",
"@mermaid-js/layout-elk": "0.2.1",
"@primer/octicons": "19.24.1",
"@replit/codemirror-indentation-markers": "6.5.3",
+9 -9
View File
@@ -89,8 +89,8 @@ importers:
specifier: 1.2.3
version: 1.2.3
'@mcaptcha/vanilla-glue':
specifier: 0.1.0-alpha-3
version: 0.1.0-alpha-3
specifier: 0.1.0-rc2
version: 0.1.0-rc2
'@mermaid-js/layout-elk':
specifier: 0.2.1
version: 0.2.1(mermaid@11.14.0)
@@ -978,11 +978,11 @@ packages:
'@marijn/find-cluster-break@1.0.2':
resolution: {integrity: sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==}
'@mcaptcha/core-glue@0.1.0-alpha-5':
resolution: {integrity: sha512-16qWm5O5X0Y9LXULULaAks8Vf9FNlUUBcR5KDt49aWhFhG5++JzxNmCwQM9EJSHNU7y0U+FdyAWcGmjfKlkRLA==}
'@mcaptcha/core-glue@0.1.0-rc1':
resolution: {integrity: sha512-P4SgUioJDR38QpnP9sPY72NyaYex8MXD6RbzrfKra+ngamT26XjqVZEHBiZU2RT7u0SsWhuko4N1ntNOghsgpg==}
'@mcaptcha/vanilla-glue@0.1.0-alpha-3':
resolution: {integrity: sha512-GT6TJBgmViGXcXiT5VOr+h/6iOnThSlZuCoOWncubyTZU9R3cgU5vWPkF7G6Ob6ee2CBe3yqBxxk24CFVGTVXw==}
'@mcaptcha/vanilla-glue@0.1.0-rc2':
resolution: {integrity: sha512-LDjn9lrKioJ3zwaQOfql7PXsnxCAHg7b1rPw7G0OxpvVE7xLB/a40SHfIIiocce2VS9TPI4MbcKm5pcuy8fU5g==}
'@mermaid-js/layout-elk@0.2.1':
resolution: {integrity: sha512-MX9jwhMyd5zDcFsYcl3duDUkKhjVRUCGEQrdCeNV5hCIR6+3FuDDbRbFmvVbAu15K1+juzsYGG+K8MDvCY1Amg==}
@@ -4856,11 +4856,11 @@ snapshots:
'@marijn/find-cluster-break@1.0.2': {}
'@mcaptcha/core-glue@0.1.0-alpha-5': {}
'@mcaptcha/core-glue@0.1.0-rc1': {}
'@mcaptcha/vanilla-glue@0.1.0-alpha-3':
'@mcaptcha/vanilla-glue@0.1.0-rc2':
dependencies:
'@mcaptcha/core-glue': 0.1.0-alpha-5
'@mcaptcha/core-glue': 0.1.0-rc1
'@mermaid-js/layout-elk@0.2.1(mermaid@11.14.0)':
dependencies:
+1 -1
View File
@@ -64,7 +64,7 @@ func prepareCommonAuthPageData(ctx *context.Context, opt CommonAuthOptions) {
ctx.Data["RecaptchaSitekey"] = setting.Service.RecaptchaSitekey
ctx.Data["HcaptchaSitekey"] = setting.Service.HcaptchaSitekey
ctx.Data["McaptchaSitekey"] = setting.Service.McaptchaSitekey
ctx.Data["McaptchaURL"] = setting.Service.McaptchaURL
ctx.Data["McaptchaURL"] = strings.TrimSuffix(setting.Service.McaptchaURL, "/")
ctx.Data["CfTurnstileSitekey"] = setting.Service.CfTurnstileSitekey
if setting.Service.CaptchaType == setting.ImageCaptcha {
ctx.Data["Captcha"] = context.GetImageCaptcha()
+1 -1
View File
@@ -48,7 +48,7 @@ func GetImageCaptcha() *captcha.Captcha {
const (
gRecaptchaResponseField = "g-recaptcha-response"
hCaptchaResponseField = "h-captcha-response"
mCaptchaResponseField = "m-captcha-response"
mCaptchaResponseField = "mcaptcha__token" // this form key is hard-coded in the mcaptcha frontend library
cfTurnstileResponseField = "cf-turnstile-response"
)
+4 -1
View File
@@ -19,7 +19,10 @@
{{else if eq .CaptchaType "mcaptcha"}}
<div class="inline field tw-text-center">
<div class="m-captcha-style" id="mcaptcha__widget-container"></div>
<div id="captcha" data-captcha-type="m-captcha" data-sitekey="{{.McaptchaSitekey}}" data-instance-url="{{.McaptchaURL}}"></div>
<label id="mcaptcha__token-label" hidden data-mcaptcha_url="{{.McaptchaURL}}/widget?sitekey={{.McaptchaSitekey}}">
<input id="mcaptcha__token" name="mcaptcha__token">{{/* the id and name are hard-coded in the library, cant't be changed */}}
</label>
<div id="captcha" data-captcha-type="m-captcha"></div>
</div>
{{else if eq .CaptchaType "cfturnstile"}}
<div class="inline field tw-text-center">
+4 -16
View File
@@ -34,22 +34,10 @@ export async function initCaptcha() {
break;
}
case 'm-captcha': {
const mCaptcha = await import('@mcaptcha/vanilla-glue');
// FIXME: the mCaptcha code is not right, it's a miracle that the wrong code could run
// * the "vanilla-glue" has some problems with es6 module.
// * the INPUT_NAME is a "const", it should not be changed.
// * the "mCaptcha.default" is actually the "Widget".
mCaptcha.INPUT_NAME = 'm-captcha-response';
const instanceURL = captchaEl.getAttribute('data-instance-url')!;
new mCaptcha.default({
siteKey: {
instanceUrl: new URL(instanceURL),
key: siteKey,
},
});
// ref: https://github.com/mCaptcha/glue/blob/master/packages/vanilla/README.md
// sample: https://github.com/mCaptcha/glue/blob/master/packages/vanilla/static/embeded.html
// @mcaptcha/vanilla-glue 0.1.0-rc2 auto-runs on module load, use the existing elements to render.
await import('@mcaptcha/vanilla-glue');
break;
}
default: