-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
[PM-13115] Allow users to disable extension content script injections by domain #11826
base: main
Are you sure you want to change the base?
Conversation
77d3472
to
e8ddd67
Compare
No New Or Fixed Issues Found |
308c302
to
2695a47
Compare
@@ -67,7 +66,6 @@ import { PopupPageComponent } from "../../../platform/popup/layout/popup-page.co | |||
JslibModule, | |||
LinkModule, | |||
PopOutComponent, | |||
PopupFooterComponent, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PopupFooterComponent
was not in use anywhere here or in the template
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file is largely a copy of apps/browser/src/autofill/popup/settings/excluded-domains.component.ts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have an open bug for the existing UI here PM-13808 with the input styling. Do you think we can get that fixed so we don't duplicate the UI into this new component?
@@ -3,6 +3,7 @@ | |||
[ciphers]="ciphers" | |||
[title]="'autofillSuggestions' | i18n" | |||
[showRefresh]="showRefresh" | |||
[sectionIndicators]="sectionIndicators" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This concept allows for the conditional addition of icon indicators alongside the section title (in this case, an informational icon indicating the view contains ciphers for a domain that has been added to the user's block list).
<bit-banner | ||
*ngIf="vaultState !== VaultStateEnum.Empty && showScriptInjectionIsBlockedBanner" | ||
id="domain-script-injection-blocked-banner" | ||
bannerType="info" | ||
(onClose)="handleScriptInjectionIsBlockedBannerDismiss()" | ||
> | ||
{{ "autofillBlockedNotice" | i18n }} | ||
</bit-banner> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Follow up work will ultimately leverage the pop up page component slot added in #12279
this.domainSettingsService | ||
.setBlockedInteractionsUris({ | ||
...blockedURIs, | ||
[this.autofillTabHostname]: { bannerIsDismissed: true }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
using the existing NeverDomains
data shape give us tons of flexibility in the future if we implement more granular injection-blocking options.
As it is, we could merge the neverDomains
state concept (expressed in the interface as "Excluded Domains" and currently used to allow users to block the notification bar on specified domains) into blockedInteractionsUris
concept with a state migration.
For example (not a well-considered data shape, just for illustrative purposes):
{
"banking-portal.real-tld": {
"blockedInjections": null, // all injections blocked
"dismissedMessages": ['autofillBlockedBanner']
},
"duckduckgo.com": {
"blockedInjections": ["notifications", "inline-menu"],
"dismissedMessages": []
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For example (not a well-considered data shape, just for illustrative purposes):
💭 You might want to update this example to account for our "no-null" guidance. If you want to keep the example short, I'd just swap out the null
for true
or "all"
(no list).
A more comprehensive example that would be easier to port to Rust (as an enum
) uses a discriminated union.
type ScriptType = "notifications" | "inline-menu";
type Injectable = { type: "allow-all" } | { type: "deny-list", injections: ScriptType[] } | { type: "deny-all" };
if (!injectionAllowedInTab) { | ||
throw new Error("This URI of this tab is on the blocked domains list."); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is purposeful blocking, no? Do we want a visible error like this?
fe32841
to
1dd180e
Compare
…s to autofill settings
… is on the blocked domains list
@@ -93,6 +102,7 @@ describe("FilelessImporterBackground ", () => { | |||
}); | |||
|
|||
it("posts a message to the port indicating that the fileless import feature is disabled if the user's auth status is not unlocked", async () => { | |||
(firstValueFrom as jest.Mock).mockResolvedValue(false); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
♻️ firstValueFrom
may be used in many places in the code. This line makes every call return false
, which is almost certainly incorrect behavior. The observable passed to firstValueFrom
should be mocked instead.
🤔 If firstValueFrom
is being called from within an autofill API, consider implementing a fake for the API or some other means to simulate the awaited observable. If it's being called from tools code, then I'll follow up with the tools team to fix the test.
blockedInteractionsUris$: Observable<NeverDomains>; | ||
setBlockedInteractionsUris: (newValue: NeverDomains) => Promise<void>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⛏️ Since these members are exported from this module and overridden in numerous tests, their behavior should be documented.
this.blockedInteractionsUris$ = combineLatest([ | ||
this.blockedInteractionsUrisState.state$, | ||
this.configService?.getFeatureFlag$(FeatureFlag.BlockBrowserInjectionsByDomain), | ||
]).pipe( | ||
map(([blockedUris, blockBrowserInjectionsByDomainEnabled]) => { | ||
if (!blockBrowserInjectionsByDomainEnabled) { | ||
return null; | ||
} | ||
|
||
return blockedUris ?? null; | ||
}), | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎨 This can be simplified if configService
becomes required.
this.configService.getFeatureFlag$(FeatureFlag.BlockBrowserInjectionsByDomain).pipe(
switchMap((enabled) => enabled ? this.blockedInteractionsUrisState.state$ : of([])),
map(blocked => blocked ?? [])
);
The main benefit of this is that it won't emit false updates from the state service when the feature is disabled.
One thing to note, however, is that combineLatest
only completes when both of its input streams complete. Since blockedInteractionsUrisState.state$
never completes, neither will blockedInteractionsUris$
.
switchMap
, on the other hand, completes once its source and argument streams complete. There's a subtle difference between the constructions because of([])
completes after emitting its last argument. If getFeatureFlag$
completes after emitting false
then the whole observable will complete.
Ultimately, which construction works best for you depends on how you consume this.blockedInteractionsUris$
. If you want it to update as soon as the flag becomes available, then combineLatest
(with logic to filter false updates) is preferable. Your notes indicate that you need to navigate in order for it to pick up the new settings, however, which leads me to believe the switchMap
approach more closely models your expectations.
📝 I also eliminated null
in my example code per ADR-14.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two questions just to start!
"message": "Autofill and other related features will not be offered for these websites. You must refresh the page for changes to take effect." | ||
}, | ||
"autofillBlockedNotice": { | ||
"message": "Autofill is blocked for this website. Review or change this in settings." |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have any way to deep link to the relevant settings page in the notice?
if (!injectionAllowedInTab) { | ||
throw new Error("This URI of this tab is on the blocked domains list."); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is purposeful blocking, no? Do we want a visible error like this?
🎟️ Tracking
PM-13115
📔 Objective
Create a concept of disabled domains for the Bitwarden extension; unlike the excluded domains in the notification settings, a page belonging to the disabled domain list would prevent the Bitwarden extension from interacting with the page at all.
Notes
block-browser-injections-by-domain
feature flagScreen capture
Kapture.2024-12-16.at.11.09.36.mp4
Kapture.2024-12-16.at.11.28.39.mp4
🦮 Reviewer guidelines
:+1:
) or similar for great changes:memo:
) or ℹ️ (:information_source:
) for notes or general info:question:
) for questions:thinking:
) or 💭 (:thought_balloon:
) for more open inquiry that's not quite a confirmed issue and could potentially benefit from discussion:art:
) for suggestions / improvements:x:
) or:warning:
) for more significant problems or concerns needing attention:seedling:
) or ♻️ (:recycle:
) for future improvements or indications of technical debt:pick:
) for minor or nitpick changes