[3.0] Theme split (wave 4, part 13) — make the login form's ajax submit actually run - #9430
Open
albertlast wants to merge 1 commit into
Open
[3.0] Theme split (wave 4, part 13) — make the login form's ajax submit actually run#9430albertlast wants to merge 1 commit into
albertlast wants to merge 1 commit into
Conversation
The login form the top menu opens has a submit handler generated into it, but
nothing has ever executed it. reqOverlayDiv() hands the response to
smc_Popup.setBody(), which assigns innerHTML, and innerHTML does not run script
elements. So the overlay has been falling back to a plain submit: the member
leaves the page they were on and lands at ?action=login2 instead of being logged
in where they stood. The focus() call in the same block never ran either.
Where the block did run, it could still be broken. The branch for a CORS origin
that is not the forum itself opens an else and never closes it:
else {
window.location.reload();
},
error: function(xhr) {
so the brace meant for success: function(data) closes the else instead, and the
$.ajax() call never parses. Served to an allowed origin, the whole script block
is a SyntaxError.
That branch is also reached more often than intended, because the guard deciding
whether to emit the handler at all tests
!in_array(Utils::$context['valid_cors_found'], ['same', 'subsite'])
and 'subsite' is not a value that exists. corsPolicyHeader() only ever sets
'same', 'subdomain', 'alias', 'additional' or 'wildcard', and User.php spells the
same check ['same', 'subdomain']. A subdomain origin is trusted everywhere else
and should be submitting the form plainly; instead it took the broken branch.
The handler moves to Themes/default/scripts/login.js, delegated from the document
so that a form arriving through innerHTML is covered like any other, and the form
opts in with data-ajax-login carrying what corsPolicyHeader() decided. Guests
load the file with the page, because that is the only way it can be there when
the overlay opens. Nothing is generated into the page any more, so the PHP
branching inside the JavaScript goes with it.
It also sends X-Requested-With, which jQuery used to add on its own and which
Login2::checkAjax() looks for.
Verified in the overlay: a wrong password now leaves the page alone and shows the
error in the overlay with the form and a fresh token behind it, and the right
password logs in without navigating. On the full page the form has no attribute
and submits normally. With CORS on, an allowed additional origin gets
data-ajax-login="additional" and a subdomain gets no attribute at all.
Signed-off-by: Mathias Albert <mathiaspapealbert@hotmail.com>
Signed-off-by: albertlast <mathiaspapealbert@hotmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Part of the #7933 split (wave 4, part 13). Login area.
The login form's ajax submit has never run. The top menu opens it through
reqOverlayDiv(), which hands the response tosmc_Popup.setBody(), whichassigns
innerHTML— andinnerHTMLdoes not execute<script>elements. Sothe generated handler sits in the DOM as inert markup and the overlay falls back
to a plain submit: the member leaves the page they were on and lands at
?action=login2instead of being logged in where they stood. Thefocus()callin the same block never ran either.
Checked on
release-3.0by opening the overlay and dispatching a cancelablesubmitat the form: nothing prevents it, and jQuery has no handlers bound toit.
Where it did run, it could still be a syntax error. The branch for a CORS
origin that is not the forum itself opens an
elseand never closes it:The brace meant for
success: function(data) {closes theelseinstead, so$.ajax()never parses. Served to an allowed origin, the whole block dies:And that branch is reached more often than intended. The guard deciding
whether to emit the handler tests
'subsite'is not a value that exists.Security::corsPolicyHeader()only eversets
'same','subdomain','alias','additional'or'wildcard', andUser.php:2407spells the same check['same', 'subdomain']. A subdomain originis trusted everywhere else in SMF and should be submitting the form plainly;
instead it fell into the broken branch.
What changes
The handler moves to
Themes/default/scripts/login.js, delegated from thedocument, so a form that arrives through
innerHTMLis covered like any other— that is what makes the overlay work. The form opts in by carrying
data-ajax-login, whose value is whatcorsPolicyHeader()decided, so thePHP branching inside the JavaScript goes away entirely.
Guests load the file with the page. That is not incidental: it is the only way
the code can be present when the overlay opens, since the ajax response has no
template layers and cannot bring its own script.
alerts.jsis loaded the sameway for members, for the same reason.
It also sends
X-Requested-With, which jQuery added on its own and whichLogin2::checkAjax()looks for. Without it the response to the submit comes backas a full page rather than a fragment.
The
setTimeout(...).focus()block is left exactly as it was. It is inert in theoverlay for the same
innerHTMLreason, but it works on the full page and it isnot what this is about.
Testing
In the overlay, on this branch: a wrong password leaves the page alone and shows
the error inside the overlay, with the form and a fresh token behind it; the
right password then logs in without navigating. On the full page the form has no
attribute and submits normally.
With CORS enabled, an allowed additional origin gets
data-ajax-login="additional"and a subdomain origin gets no attribute at all. Every emitted script block passes
node --check.Issues References (Fixes|Related|Closes)
Related to #7933