Ok, I've redone the whole shebang, hoping this'll pass muster. If not, I can do a larger refactor of the whole ConfirmEdit extension, maybe make a fresh one and introduce better machine-readable hook points into the API and form.

But I hope this'll do for now. :)

> MediaWiki core: https://gerrit.wikimedia.org/r/53793
> ConfirmEdit ext: https://gerrit.wikimedia.org/r/53794
>
> test rig: https://github.com/brion/mw-createaccount-test

Major changes from previous approach:
* instead of falling through if in API mode (dangerous if using the new extension on old core), we check the captcha in the same consistent place in a hook from LoginForm.
* We add a fairly generic hook that allows extensions to add return data via the createaccount API if they threw an abort instead of sending a generic error. This is used to append the captcha data.
* We return result='needcaptcha' explicitly if we need to pass a captcha
* Captcha data is not available until after you have a token, so this requires making two requests if you want to show a captcha before prompting for username/password.

If y'all would prefer totally fresh interfaces with a consistent machine-readable API... I can do that too, but it'd be spiffy if we could do the less invasive change first. :)

-- brion



On Mon, Mar 25, 2013 at 1:38 AM, S Page <spage@wikimedia.org> wrote:
On Thu, Mar 14, 2013 at 3:55 PM, Brion Vibber <bvibber@wikimedia.org> wrote:

> MediaWiki core: https://gerrit.wikimedia.org/r/53793
> ConfirmEdit ext: https://gerrit.wikimedia.org/r/53794
>
> So far I've tested it with the default 'math captcha' mode, with this test
> rig: https://github.com/brion/mw-createaccount-test

This is great to see.

Using your test rig or Special:APISandbox, the API return warns about
"Unrecognized parameters: 'wpCaptchaId', 'wpCaptchaWord" when I get
the captcha wrong.

It seems if the user gets the captcha wrong, there's no explicit
indication like captcha-createaccount-fail ('Incorrect or missing
confirmation code.'). Instead the API reports a generic Failure
result, and the UI presents a new captcha.

ConfirmEdit has a getMessage() to provide action-specific text like
fancycaptcha-createaccount. Perhaps the API should pass that back as
well. Otherwise the UI has to know the details of the captcha in use
so it can get a message for it.

The current CreateAccount form submission to Special:UserLogin reports
many form errors like username exists, password wrong, etc. before it
runs the AbortNewAccount hook where ConfirmEdit checks the captcha.
But APICreateAccount runs the APICreateAccountBeforeCreate hook early,
before it dummies up a login form and calls the same validation. So
users will go through the frustration of getting the captcha right
before being told their username isn't available or their password
isn't long enough.

There's also the weirdness that ApiCreateAccount winds up checking the
CAPTCHA twice. AIUI, here's the program flow:

ApiCreateAccount()
    Runs APICreateAccountBeforeCreate hook (captcha may abort)
    Creates a login forms and call $loginForm->addNewaccountInternal();
    addNewaccountInternal():
        Does a bunch of form validation
        Runs AbortNewAccount hook (captcha may abort, also
TitleBlacklist, AntiSpoof, etc. may abort)

If  ApiCreateAccount() could tell there was a captcha failure within
addNewaccountInternal and could ask the captcha to addCaptchaAPI() to
the result, then we wouldn't need the new APICreateAccountBeforeCreate
hook.

It would be nice if captcha was always checked on its own hook instead
of sharing a hook with other extensions. That would let a future
validation API run the username past TitleBlacklist and AntiSpoof
without getting shot down by the captcha.

Cheers,
--
=S Page  software engineer on E3