Conversation
67b5d89 to
2839d96
Compare
| */ | ||
| function queryShadowRoots(parent) { | ||
| return [parent, ...parent.querySelectorAll("*")] | ||
| .filter((e) => e.shadowRoot) |
There was a problem hiding this comment.
When parent is document (in the very first call), won't this .filter() line remove it from the result array, resulting in a change of behavior?
There was a problem hiding this comment.
Oops, sorry. Revised, and now tested with both a shadow-root and non-shadow-root login page.
|
Interrogating every single element on the page just to find the roots can be quite slow, and is a notable performance issue on pages with a large number of elements. I would suggest instead collating a list of shadow roots as they are created, or marking them in some way that will allow This can be done by intercepting the For example: var _attachShadow;
if (!_attachShadow) {
_attachShadow = Element.prototype.attachShadow;
Element.prototype.attachShadow = function (options) {
this.setAttribute("is-shadow", "");
return _attachShadow.call(this, options);
};
}Which allows quickly getting the roots later using |
|
Hmm, not a bad idea, the thing about that though is we have to start injecting code into every webpage at startup, whereas the current architecture only has us injecting any logic once the extension menu icon is interacted with and a password entry is selected. I would be somewhat leery of going to a model where the extension has to have access to all website data even when not actively being used, maybe it could be opt in though? |
This is true. However, the injected code would be extremely lightweight, and is essentially a noop where shadow roots aren't used.
It's not a move to that model; Browserpass already holds (and uses) the all-sites permission, and therefore already has access to all site data: |
I think this is just Firefox's way of making it revocable by the user. Chrome has a similar thing on the context menu for it. However, we hold the permission by default - it's not something we need to ask for, and unless the user has manually removed it later, we should already hold it on all existing installs.
Easy enough. Just have the injected script drop an identifier in the DOM when it runs (e.g. an attribute on the document element), and if that identifier is missing when we go to fill credentials, then gracefully fall back to the slow / expensive check-all-the-elements approach. |
|
Fair enough. Will wait to hear back from @max-baz before doing more work though, as I'd like an indication that this will be merged at some point. |
|
@erayd designed and developed a big portion of this extension, I trust his judgment and happy to get this merged as soon as you two reach the stage where you both are happy with the implementation 👍 |
|
Oh, okay! I'll fix this up as soon as I have a chance, then. |

Fairly straightforward. I just introduce a function
queryShadowRootsthat converts a single parent element into a list that contains the parent plus all shadow roots amongst its descendants. ThenqueryAllVisibleinvokes it and iterates through the results, applyingquerySelectorAllto each individual shadow root (and the original parent).I tested this and it seemed to work right away, allowing autofill to succeed on one of my sites where the login form is inside a shadow root.
I recommend viewing the diff with whitespace changes disabled.
Closes #73