Skip to content

Ask for the member's address in a box of its own - #17

Merged
JeroenDeDauw merged 2 commits into
masterfrom
separate-email-field-on-login-form
Aug 22, 2026
Merged

Ask for the member's address in a box of its own#17
JeroenDeDauw merged 2 commits into
masterfrom
separate-email-field-on-login-form

Conversation

@alistair3149

@alistair3149 alistair3149 commented Aug 21, 2026

Copy link
Copy Markdown
Member

The code route borrowed the login form's username box. A field several providers describe is
labelled by the first of them, and this one is not it, so the address box was labelled "Username",
placeholded "Enter your username" and autocompleted from the username the browser had saved. The
messages meant to say otherwise, memberaccess-auth-email-label and -help, never reached the
page. The button sending the code also sat above the button it is an alternative to, styled as the
form's primary button beside the one that already was.

Ask for the address in a field of this request's own, below the password form and behind a divider,
with a button that is progressive without being primary.

A box of its own means the request declares no username, so a code request names no account to
MediaWiki and is counted against the client IP rather than against one address. Telling one address
from another is left to the extension's own throttle, which is the tighter of the two. Declaring a
username anyway would put a second answer on a form that already has the username box, and two
requests naming different accounts is a conflict MediaWiki raises rather than resolves.

LoginThrottleTest is rewritten around that: the two cases pinning per-address counting are
replaced by ones pinning that the counting is per client IP, and by one pinning that filling both
boxes no longer raises the conflict.

Considered, omitted:

  • leading with the member route and folding the password form away, which suits a wiki whose logins
    are mostly members but hides the staff route
  • a heading over the section, which the divider and the field's own label already say
  • revisiting the wiki-wide badloginperuser captcha concession, which was made because the address
    sat in the field ConfirmEdit reads as the login subject and may no longer be needed now that it
    does not

Needs a look in a browser. composer preflight is green and the flow was driven end to end over
HTTP — code requested, mail caught, code entered, account auto-created into reader — but the
divider styling has not been seen rendered.

AI-authored — Claude Code, Opus 5 (1M context); design settled over several rounds with @alistair3149, who chose this shape over keeping the shared field and directed the button label, section heading and placeholder wording; diff not yet human-reviewed; PHPCS, PHPStan and 724 tests pass locally, flow verified end to end over HTTP, CSS not visually checked.

@codecov-commenter

codecov-commenter commented Aug 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 95.65217% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 87.29%. Comparing base (e56d3bb) to head (3f53b74).

Files with missing lines Patch % Lines
src/EntryPoints/LoginFormHandler.php 93.45% 7 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master      #17      +/-   ##
============================================
+ Coverage     86.75%   87.29%   +0.54%     
- Complexity      574      604      +30     
============================================
  Files            64       66       +2     
  Lines          1985     2125     +140     
============================================
+ Hits           1722     1855     +133     
- Misses          263      270       +7     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@alistair3149
alistair3149 force-pushed the separate-email-field-on-login-form branch 6 times, most recently from fb764fa to 5e67582 Compare August 21, 2026 17:54
@alistair3149

Copy link
Copy Markdown
Member Author

Normal:
image

With captcha:
image

@alistair3149
alistair3149 marked this pull request as ready for review August 21, 2026 17:56
@alistair3149
alistair3149 force-pushed the separate-email-field-on-login-form branch from 5e67582 to 53a9db6 Compare August 21, 2026 18:45
@JeroenDeDauw

Copy link
Copy Markdown
Member

Makes sense. Looks better than what we had before.

Did you check how this behaves with standard login being disabled?

I also wonder about the registration page behavior. Didn't look at that at all yet for this extension. For this extension login is registration if the account did not exist yet.

@alistair3149

Copy link
Copy Markdown
Member Author

Did you check how this behaves with standard login being disabled?

No I didn't know it was possible.

I also wonder about the registration page behavior. Didn't look at that at all yet for this extension. For this extension login is registration if the account did not exist yet.

While I haven't checked the account creation page, the first concern I raised with Claude was about account creation being disabled, and it said that it is not an issue.

@JeroenDeDauw

Copy link
Copy Markdown
Member

Fixing merge conflicts

alistair3149 and others added 2 commits August 22, 2026 14:50
The code route borrowed the login form's username box. A field several providers
describe is labelled by the first of them, and this one is not it, so the address
box was labelled "Username", placeholded "Enter your username" and autocompleted
from the username the browser had saved. The messages meant to say otherwise,
memberaccess-auth-email-label and -help, never reached the page. The button sending
the code also sat above the button it is an alternative to, styled as the form's
primary button beside the one that already was.

Ask for the address in a field of this request's own, typed as one so that a phone
offers the keyboard for it and a browser fills it from the right place, below the
password form and behind a divider, with a button that is progressive without being
primary.

A box of its own means the request declares no username, so a code request names no
account to MediaWiki and is counted against the client IP rather than against one
address. Telling one address from another is left to the extension's own throttle,
which is the tighter of the two. Declaring a username anyway would put a second
answer on a form that already has the username box, and two requests naming
different accounts is a conflict MediaWiki raises rather than resolves.

Considered, omitted:

* leading with the member route and folding the password form away, which suits a
  wiki whose logins are mostly members but hides the staff route
* a heading over the section, which the divider and the field's own label already
  say
* revisiting the wiki-wide badloginperuser captcha concession, which was made
  because the address sat in the field ConfirmEdit reads as the login subject and
  may no longer be needed now that it does not

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The screen asking for the code said nothing about where it went, offered no way to
ask for another, and no way back to the address box. A visitor who mistyped their
address had nothing to see it by and nowhere to go.

Name the address back, from the authentication session rather than the form, and
offer two sentences under the code box: another code, and a way back to the start
of the login form. Starting the form again already asks for an address rather than
resuming the code screen, so only the way to it was missing.

What is named is what was typed, so the screen says the same for an admitted
address and one the allowlist has never heard of. It is named as a plaintext
parameter: the screen it appears on is parsed as wikitext, and an address is
nothing but a trimmed string, so given as an ordinary parameter one holding a
transclusion would fetch the page it names into the login screen for anyone at all
to read.

Asking for another code goes through the same use case as the first, so it is
counted by the same throttle, and it replaces the handle the session holds, so the
code sent before it stops working. A refusal used to answer by failing the login,
which threw the visitor off the screen and took the code they were holding with
them; now it leaves them there, withdraws the offer, and says why. A code sent
after a refusal offers it again.

Each sentence is one piece of markup rather than a prompt field beside a button
field. A form field is laid out as a block within a block, and a button is drawn as
a box whatever display it is given, so two of them will not read as one line. The
button in the sentence is real, but the field it belongs to is what the form
collects the press from, so that field stays described and is hidden instead.

The code box says what it takes: a one-time code, of the length the generator makes
them, digits only. A pattern is checked before the form is submitted whichever
button did it, so asking for another code is exempted from that check, and the box
itself is optional — required, it would have to be filled before the button asking
for another code could be pressed.

Considered, omitted:

* a countdown, either to the code expiring or to the allowance freeing, which would
  make this the extension's first JavaScript for something the withdrawn offer
  already says
* leading with the member route and folding the password form away
* inputmode on the code box, which HTMLForm passes no attribute through for

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
@JeroenDeDauw
JeroenDeDauw force-pushed the separate-email-field-on-login-form branch from 69ced38 to 3f53b74 Compare August 22, 2026 13:00
@JeroenDeDauw

Copy link
Copy Markdown
Member

Rebased onto master, which had moved on to #20. Textual conflicts in README.md and both i18n files, plus one in MemberAuthenticationProvider, where both sides had rewritten the line that verifies an entered code: it now ungroups first and then answers an empty box, keeping both.

One conflict was not textual, and neither branch carries it alone. #20 mails the code in groups of four and takes the spaces back off before verifying, so 1234 5678 can be pasted. This branch's code box was maxlength="8" with a [0-9]{8} pattern, which would have cut that paste to eight characters and then refused what was left. The box now takes the code the way the mail shows it: maxlength is the grouped length, and the pattern is the digits with spaces allowed among them. DisplayedCode gained groupedLength() so grouping stays known in one place, the placeholder follows it (1234 5678), and two tests pin the box accepting a grouped code and refusing a short one. The paragraph in the second commit describing the box was updated to match.

Checked on a MediaWiki 1.43.8 install: PHPCS and PHPStan clean, and 767 of 768 tests pass — the one error, in MediaWikiMemberBlockerTest, reproduces on unmodified master in that same install and is green here on CI. The flow was driven end to end: code requested, mail caught, 8609 0639 pasted with its space, logged in and auto-created into reader. Chromium's own constraint validation accepts the grouped code and refuses a short one.

The divider styling is no longer unseen. It renders as a rule with "or" centred between the password form and the email section, and each of the two code-screen sentences reads as one line.

AI-authored — Claude Code, Fable 5 (max); one-line ask from @JeroenDeDauw to resolve the conflicts, no redirection; the rebase resolution is not yet human-reviewed; checks and the end-to-end flow run locally on MW 1.43.8, CI green.

@JeroenDeDauw
JeroenDeDauw merged commit c7a5b63 into master Aug 22, 2026
6 checks passed
@JeroenDeDauw
JeroenDeDauw deleted the separate-email-field-on-login-form branch August 22, 2026 13:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants