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

[Form] Check if form.elements is iterable before destructuring #629

Merged
merged 1 commit into from
Aug 8, 2024

Conversation

dbajpeyi
Copy link
Collaborator

@dbajpeyi dbajpeyi commented Aug 7, 2024

Reviewer: @shakyShane
Asana: https://app.asana.com/0/1205996472158114/1207750680043135/f

Description

Some sites potentially can override the form.elements behavior, making it not iteratable, causing autofill breakage.

Steps to test

  1. npm run build
  2. Add to android's package.json and npm install,
  3. Run android studio/other IDE to run emulator
  4. Go to usa.experian.com/login/index
  5. Autofill should work normally (saves new password, shows key icon, autofills and triggers auto-submit)

@dbajpeyi dbajpeyi force-pushed the dbajpeyi/uniterable-form branch 2 times, most recently from 48ea818 to 23deab6 Compare August 7, 2024 06:27
@dbajpeyi dbajpeyi changed the title fix: check if form elements are iterable [Form] Check if form.elements is iterable before destructuring Aug 7, 2024
Comment on lines +403 to +408
// Some sites seem to be overriding `form.elements`, so we need to check if it's still iterable.
if (
this.form instanceof HTMLFormElement &&
this.form.elements != null &&
Symbol.iterator in Object(this.form.elements)
) {
Copy link
Collaborator

@shakyShane shakyShane Aug 7, 2024

Choose a reason for hiding this comment

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

This would exclude those sites with an override form.elements though? perhaps it's still array-like in those cases and we could just do a manual thing like this (which would be faster too 😂)

const formElements = [];
for (let i = 0; i < this.form.elements.length; i++) {
  const el = this.form.elements[i];
  if (el.matches(selector)) {
    formElements.push(el);
  }
}

Also might be worth checking if Array.from() solves the site in question too - (you'll need to check the spec, as to what .from accepts)

either way, if this pops up again, we should probably just make a small helper, like array() that takes array-like things and packages them up into a regular array, so that map/filter etc work as expected.

You could also make it accept null/undefined too, returning an empty array. so this entire block might look like:

const formElements = array(this.form?.elements).filter(el => el.matches(selector))

Copy link
Member

Choose a reason for hiding this comment

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

Let’s not get ahead of ourselves 😅. There’s no evidence of this being a widespread issue. We’ve only found one site and their override is not iterable, if I remember correctly. Until we have reason to introduce the extra complexity I’d be inclined to keep things simple.

Copy link
Collaborator Author

@dbajpeyi dbajpeyi Aug 7, 2024

Choose a reason for hiding this comment

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

Sorry, I still wanted to do run some tests before opening for review, but my android setup is broken (getting help in android channel).

I would not generalize it too far yet with the custom array solution, I think your first suggestion makes sense in the else part.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Of course, I was just giving an alternative solution, as I said 'if this pops up again' :)

I didn't want to use 'Symbol.iterator in Object(this.form.elements)' just because it would exclude the form - is that the intention?

if so, you can discard my comments of course :)

Copy link
Collaborator Author

@dbajpeyi dbajpeyi Aug 8, 2024

Choose a reason for hiding this comment

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

Symbol.iterator in Object(this.form.elements) in this case will exclude the extra shadow checks and some nice goodies we get e.g safeguard against broken markups (based on the comments, haven't tested that), but it still falls back to querySelectorAll (in the else part) which ends up working for this specific site luckily:

android-form-elements.mp4

Of course it'd suck if we had shadow inputs here, but we're lucky :D

If we see more of these, we should figure out a way to abstract out the form.elements totally agree! But that's implementation dependent on what has been done to form.elements. Although I think it's a ridiculous thing to do to make a collection non-iterable. Not sure how often this would happen.

@dbajpeyi dbajpeyi marked this pull request as ready for review August 8, 2024 08:05
Copy link
Collaborator

@shakyShane shakyShane left a comment

Choose a reason for hiding this comment

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

Thanks!

@dbajpeyi dbajpeyi merged commit ff7f13d into main Aug 8, 2024
1 check passed
@dbajpeyi dbajpeyi deleted the dbajpeyi/uniterable-form branch August 8, 2024 09:22
CDRussell pushed a commit to duckduckgo/Android that referenced this pull request Aug 13, 2024
Task/Issue URL:
https://app.asana.com/0/1208019514044452/1208019514044452
Autofill Release:
https://github.com/duckduckgo/duckduckgo-autofill/releases/tag/13.0.0


## Description
Updates Autofill to version
[13.0.0](https://github.com/duckduckgo/duckduckgo-autofill/releases/tag/13.0.0).

### Autofill 13.0.0 release notes
## What's Changed
Minor version update, adding a new feature behind
`unknown_username_categorization` featureToggle, but the toggle is
optional in JS and doesn't introduce regression.
* Update password-related json files (2024-07-30) by @daxmobile in
duckduckgo/duckduckgo-autofill#621
* [Form] allow reconciling full credential by @dbajpeyi in
duckduckgo/duckduckgo-autofill#620
* [Form] Check if form.elements is iterable before destructuring by
@dbajpeyi in duckduckgo/duckduckgo-autofill#629
* [Matching] Update newPassword form regex by @dbajpeyi in
duckduckgo/duckduckgo-autofill#628
* [Form] re-decorate input if there is 1 unknown username by @dbajpeyi
in duckduckgo/duckduckgo-autofill#619


**Full Changelog**:
duckduckgo/duckduckgo-autofill@12.1.0...13.0.0

## Steps to test
This release has been tested during autofill development. For smoke test
steps see [this
task](https://app.asana.com/0/1198964220583541/1200583647142330/f).

Co-authored-by: dbajpeyi <3018923+dbajpeyi@users.noreply.github.com>
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