Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

autofocus: Loosen fragment identifier restriction #6204

Merged
merged 3 commits into from
Feb 26, 2021

Conversation

tkent-google
Copy link
Collaborator

@tkent-google tkent-google commented Dec 9, 2020

Fixes #5252

Before this change:
foo.html# => autofocus works
foo.html#top => autofocus does not work
foo.html#existingId => autofocus does not work
foo.html#non-existent => autofocus does not work

After this change:
foo.html# => autofocus works
foo.html#top => autofocus works
foo.html#existingId => autofocus does not work
foo.html#non-existent => autofocus works

(See WHATWG Working Mode: Changes for more details.)


/interaction.html ( diff )

@domenic
Copy link
Member

domenic commented Dec 9, 2020

The worry I have here is exposing the presence or absence of a target element for cross-origin ancestor documents. That seems not great security-wise. Also, it is probably hard to implement, in out-of-process-iframe cases?

@tkent-google
Copy link
Collaborator Author

The worry I have here is exposing the presence or absence of a target element for cross-origin ancestor documents. That seems not great security-wise. Also, it is probably hard to implement, in out-of-process-iframe cases?

I thought we avoided such situations by "If target's origin is not the same as the origin of topDocument, then return." in the autofocus element insertion steps, however I found it didn't work well if an iframe in the middle had a different origin.

Top frame: origin-1
Child iframe: origin-2
Grandchild iframe: origin-1

I updated the step to solve this issue.

Copy link
Member

@domenic domenic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. @annevk, could you double-check, since I know ancestor-crawling is always a bit fragile? Note that "flush autofocus candidates" is only ever run when the document is fully active, so I think the current text is good.

Also, I tend to agree with @tkent-google that probably this minor tweak (almost a bug fix) is covered by Mozilla's previous endorsement of the autofocus revamp, but your take on that would be appreciated as well.

@tkent-google
Copy link
Collaborator Author

Top frame: origin-1
Child iframe: origin-2
Grandchild iframe: origin-1

Another solution would be to drop different origin documents in the inclusiveAncestorDocuments collection step. What do you think?

@annevk
Copy link
Member

annevk commented Dec 11, 2020

I'm not sure I understand the security setup. Couldn't a same-origin document (with respect to the top-level document) always steal focus, regardless of documents in between? Or would this not work if one of the documents in between had focus? (In which case the check should probably be relative to who has focus.)

@domenic
Copy link
Member

domenic commented Dec 11, 2020

Another solution would be to drop different origin documents in the inclusiveAncestorDocuments collection step. What do you think?

I slightly prefer your current setup, because it seems more obviously stopping the bad thing at the source. But I don't have a strong preference.

I'm not sure I understand the security setup. Couldn't a same-origin document (with respect to the top-level document) always steal focus, regardless of documents in between? Or would this not work if one of the documents in between had focus? (In which case the check should probably be relative to who has focus.)

The attack scenario I'm concerned about is a small cross-origin information leak, not about focus stealing. In particular, consider A1 -> B -> A2 where B can be in two states:

  1. B has a target element, e.g., B is currently navigated to https://b.example.com/#foo and an element with ID foo exists

  2. B has no target element, e.g., B is currently navigated to https://b.example.com/#foo and no element with ID foo exists

Now, A2 contains <input autofocus>. Without the step introduced in ea99b99 , A2 can tell:

  • If the input is focused, then B is in state 2.
  • In the input remains unfocused, then B is in state 1.

Does that make sense?

@annevk
Copy link
Member

annevk commented Dec 14, 2020

The longer I look at this algorithm the more confused I get. We only run "flush autofocus candidates" for a top-level document. Why would it ever have ancestors?

If that's a misunderstanding somehow I don't understand why it cares about the fragment of ancestor documents and not whether or not they are focused. If a document has a fragment and then the user scrolls around, it seems the fragment is no longer relevant even if it's still there?

@tkent-google
Copy link
Collaborator Author

We only run "flush autofocus candidates" for a top-level document. Why would it ever have ancestors?

The candidates can contain elements in descendant documents.

If that's a misunderstanding somehow I don't understand why it cares about the fragment of ancestor documents and not whether or not they are focused. If a document has a fragment and then the user scrolls around, it seems the fragment is no longer relevant even if it's still there?

A user or a code expects that a document is scrolled to a specific position by a URL fragment. Autofocus should not break the expectation. If autofocus worked after scroll-to-fragment, the document would be scrolled unexpectedly without any user activation.

@annevk
Copy link
Member

annevk commented Dec 15, 2020

Thanks! But doesn't it mean that if we have a single document whose fragment is not empty, that upon some user action inserts a new widget that contains autofocus, it would not get focus? But focus() would? (This might make more sense if "autofocus processed flag" was always set once a document was "loaded", but that doesn't seem to be the case.)

I also come back to the question of who has focus. In Domenic's scenario, assuming A1 used that URL with fragment for B, B doesn't have focus afaik, so it seems fine for A2 to take focus from A1, regardless of how B is scrolled.

Now in the setup where A1 loads B without fragment and B loads A2, and then the user navigates B to a fragment, it doesn't make sense for A2 to steal focus, but mostly because that would be across origins. Setting the "autofocus processed flag" at some point during loading would also help with that.

source Outdated
<span data-x="concept-document-url">URL</span>'s
<span data-x="concept-url-fragment">fragment</span> is not empty, then:</p>
is not <var>topDocument</var> itself, or <var>topDocument</var> has non-null <span>target
element</span>, then:</p>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't this quite racy if target element happens to be somewhere close to the end of the document?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. the order of scroll-to-fragment and the autofocus processing is not deterministic. But regardless of their order, the final focused element will be the :target element.

@tkent-google
Copy link
Collaborator Author

Thanks! But doesn't it mean that if we have a single document whose fragment is not empty, that upon some user action inserts a new widget that contains autofocus, it would not get focus? But focus() would? (This might make more sense if "autofocus processed flag" was always set once a document was "loaded", but that doesn't seem to be the case.)

Yes, it does. Note that this PR changes "fragment is not empty" to ":target exists".
As for the difference between autofocus and focus(), I think autofocus is basically a feature for the loading time. Setting "autofocus processed flag" on finishing document load makes sense, but I'm afraid it will break too many sites.

I also come back to the question of who has focus. In Domenic's scenario, assuming A1 used that URL with fragment for B, B doesn't have focus afaik, so it seems fine for A2 to take focus from A1, regardless of how B is scrolled.

Yes. If the fragment is provided by the code in A1, not by the user, I think it's ok that autofocus in A2 works.

Now in the setup where A1 loads B without fragment and B loads A2, and then the user navigates B to a fragment, it doesn't make sense for A2 to steal focus, but mostly because that would be across origins. Setting the "autofocus processed flag" at some point during loading would also help with that.

Yeah, it looks to work well.

Summary of my opinion:

  • I think setting "autofocus processed flag" on finishing document load is risky for site compatibility.
  • Nested frame like A1 -> B -> A2 must be rare. I guess disabling autofocus in A2 is safer than setting "autofocus processed flag" on finishing document load.

@annevk
Copy link
Member

annevk commented Jan 13, 2021

The other question I had is why it needs to be disabled in this way and why the origin check cannot be with the origin of the document that currently has focus.

Base automatically changed from master to main January 15, 2021 07:58
@tkent-google
Copy link
Collaborator Author

The other question I had is why it needs to be disabled in this way

Do you have other ideas?

why the origin check cannot be with the origin of the document that currently has focus.

It would not make much sense because if a descendant document has focus, 'autofocus' should not work at all.

@annevk
Copy link
Member

annevk commented Jan 21, 2021

I see, I guess that means you have to go through ancestors and then I don't really have other ideas.

Copy link
Member

@domenic domenic left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. I'll give folks a day or so to comment and then merge this.

@domenic domenic merged commit 3ffa1ba into whatwg:main Feb 26, 2021
tkent-google added a commit to web-platform-tests/wpt that referenced this pull request Mar 1, 2021
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this pull request Mar 2, 2021
…ment

This CL implements the specification change of [1].

- Check existence of :target instead of a non-empty fragment
- Accept autofocus only if all ancestors are in the same origin
- Fix WPT document-with-fragment-valid.html

[1] whatwg/html#6204

Bug: 1046357
Change-Id: Ic83b00b7b48ee94f087974368b5daec98849fc49
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this pull request Mar 2, 2021
…ment

This CL implements the specification change of [1].

- Check existence of :target instead of a non-empty fragment
- Accept autofocus only if all ancestors are in the same origin
- Fix WPT document-with-fragment-valid.html

[1] whatwg/html#6204

Bug: 1046357
Change-Id: Ic83b00b7b48ee94f087974368b5daec98849fc49
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2727997
Commit-Queue: Mason Freed <masonfreed@chromium.org>
Auto-Submit: Kent Tamura <tkent@chromium.org>
Reviewed-by: Mason Freed <masonfreed@chromium.org>
Cr-Commit-Position: refs/heads/master@{#859029}
chromium-wpt-export-bot pushed a commit to web-platform-tests/wpt that referenced this pull request Mar 2, 2021
…ment

This CL implements the specification change of [1].

- Check existence of :target instead of a non-empty fragment
- Accept autofocus only if all ancestors are in the same origin
- Fix WPT document-with-fragment-valid.html

[1] whatwg/html#6204

Bug: 1046357
Change-Id: Ic83b00b7b48ee94f087974368b5daec98849fc49
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2727997
Commit-Queue: Mason Freed <masonfreed@chromium.org>
Auto-Submit: Kent Tamura <tkent@chromium.org>
Reviewed-by: Mason Freed <masonfreed@chromium.org>
Cr-Commit-Position: refs/heads/master@{#859029}
moz-v2v-gh pushed a commit to mozilla/gecko-dev that referenced this pull request Mar 15, 2021
… documents with fragments, a=testonly

Automatic update from web-platform-tests
html: Update autofocus tests in cases of documents with fragments (#26815)

Specification change: whatwg/html#6204
Issue: whatwg/html#5252

--

wpt-commits: d05fefcf165fd03947238957b00b0ca35c45213c
wpt-pr: 26815
moz-v2v-gh pushed a commit to mozilla/gecko-dev that referenced this pull request Mar 15, 2021
…URL contains a non-empty fragment, a=testonly

Automatic update from web-platform-tests
html: autofocus should work even if the URL contains a non-empty fragment

This CL implements the specification change of [1].

- Check existence of :target instead of a non-empty fragment
- Accept autofocus only if all ancestors are in the same origin
- Fix WPT document-with-fragment-valid.html

[1] whatwg/html#6204

Bug: 1046357
Change-Id: Ic83b00b7b48ee94f087974368b5daec98849fc49
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2727997
Commit-Queue: Mason Freed <masonfreed@chromium.org>
Auto-Submit: Kent Tamura <tkent@chromium.org>
Reviewed-by: Mason Freed <masonfreed@chromium.org>
Cr-Commit-Position: refs/heads/master@{#859029}

--

wpt-commits: 4f0a3ea67ef9134ebe34463faec6ba8f6adbf37c
wpt-pr: 27853
gecko-dev-updater pushed a commit to marco-c/gecko-dev-comments-removed that referenced this pull request Mar 15, 2021
… documents with fragments, a=testonly

Automatic update from web-platform-tests
html: Update autofocus tests in cases of documents with fragments (#26815)

Specification change: whatwg/html#6204
Issue: whatwg/html#5252

--

wpt-commits: d05fefcf165fd03947238957b00b0ca35c45213c
wpt-pr: 26815

UltraBlame original commit: 05e859af38058db1930f020a6310d3de418c3c27
gecko-dev-updater pushed a commit to marco-c/gecko-dev-comments-removed that referenced this pull request Mar 15, 2021
…URL contains a non-empty fragment, a=testonly

Automatic update from web-platform-tests
html: autofocus should work even if the URL contains a non-empty fragment

This CL implements the specification change of [1].

- Check existence of :target instead of a non-empty fragment
- Accept autofocus only if all ancestors are in the same origin
- Fix WPT document-with-fragment-valid.html

[1] whatwg/html#6204

Bug: 1046357
Change-Id: Ic83b00b7b48ee94f087974368b5daec98849fc49
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2727997
Commit-Queue: Mason Freed <masonfreedchromium.org>
Auto-Submit: Kent Tamura <tkentchromium.org>
Reviewed-by: Mason Freed <masonfreedchromium.org>
Cr-Commit-Position: refs/heads/master{#859029}

--

wpt-commits: 4f0a3ea67ef9134ebe34463faec6ba8f6adbf37c
wpt-pr: 27853

UltraBlame original commit: 308a083fb3a37864533ec934d2acd986f6a27526
gecko-dev-updater pushed a commit to marco-c/gecko-dev-wordified that referenced this pull request Mar 15, 2021
… documents with fragments, a=testonly

Automatic update from web-platform-tests
html: Update autofocus tests in cases of documents with fragments (#26815)

Specification change: whatwg/html#6204
Issue: whatwg/html#5252

--

wpt-commits: d05fefcf165fd03947238957b00b0ca35c45213c
wpt-pr: 26815

UltraBlame original commit: 05e859af38058db1930f020a6310d3de418c3c27
gecko-dev-updater pushed a commit to marco-c/gecko-dev-wordified that referenced this pull request Mar 15, 2021
…URL contains a non-empty fragment, a=testonly

Automatic update from web-platform-tests
html: autofocus should work even if the URL contains a non-empty fragment

This CL implements the specification change of [1].

- Check existence of :target instead of a non-empty fragment
- Accept autofocus only if all ancestors are in the same origin
- Fix WPT document-with-fragment-valid.html

[1] whatwg/html#6204

Bug: 1046357
Change-Id: Ic83b00b7b48ee94f087974368b5daec98849fc49
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2727997
Commit-Queue: Mason Freed <masonfreedchromium.org>
Auto-Submit: Kent Tamura <tkentchromium.org>
Reviewed-by: Mason Freed <masonfreedchromium.org>
Cr-Commit-Position: refs/heads/master{#859029}

--

wpt-commits: 4f0a3ea67ef9134ebe34463faec6ba8f6adbf37c
wpt-pr: 27853

UltraBlame original commit: 308a083fb3a37864533ec934d2acd986f6a27526
gecko-dev-updater pushed a commit to marco-c/gecko-dev-wordified-and-comments-removed that referenced this pull request Mar 15, 2021
… documents with fragments, a=testonly

Automatic update from web-platform-tests
html: Update autofocus tests in cases of documents with fragments (#26815)

Specification change: whatwg/html#6204
Issue: whatwg/html#5252

--

wpt-commits: d05fefcf165fd03947238957b00b0ca35c45213c
wpt-pr: 26815

UltraBlame original commit: 05e859af38058db1930f020a6310d3de418c3c27
gecko-dev-updater pushed a commit to marco-c/gecko-dev-wordified-and-comments-removed that referenced this pull request Mar 15, 2021
…URL contains a non-empty fragment, a=testonly

Automatic update from web-platform-tests
html: autofocus should work even if the URL contains a non-empty fragment

This CL implements the specification change of [1].

- Check existence of :target instead of a non-empty fragment
- Accept autofocus only if all ancestors are in the same origin
- Fix WPT document-with-fragment-valid.html

[1] whatwg/html#6204

Bug: 1046357
Change-Id: Ic83b00b7b48ee94f087974368b5daec98849fc49
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2727997
Commit-Queue: Mason Freed <masonfreedchromium.org>
Auto-Submit: Kent Tamura <tkentchromium.org>
Reviewed-by: Mason Freed <masonfreedchromium.org>
Cr-Commit-Position: refs/heads/master{#859029}

--

wpt-commits: 4f0a3ea67ef9134ebe34463faec6ba8f6adbf37c
wpt-pr: 27853

UltraBlame original commit: 308a083fb3a37864533ec934d2acd986f6a27526
mjfroman pushed a commit to mjfroman/moz-libwebrtc-third-party that referenced this pull request Oct 14, 2022
…ment

This CL implements the specification change of [1].

- Check existence of :target instead of a non-empty fragment
- Accept autofocus only if all ancestors are in the same origin
- Fix WPT document-with-fragment-valid.html

[1] whatwg/html#6204

Bug: 1046357
Change-Id: Ic83b00b7b48ee94f087974368b5daec98849fc49
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2727997
Commit-Queue: Mason Freed <masonfreed@chromium.org>
Auto-Submit: Kent Tamura <tkent@chromium.org>
Reviewed-by: Mason Freed <masonfreed@chromium.org>
Cr-Commit-Position: refs/heads/master@{#859029}
GitOrigin-RevId: 4cdd12b94ff1128e83d4e9c801fbf1d26d546e8d
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

Fragment check in the "flush autofocus candidate" algorithm caused a compatibility issue
4 participants