1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-19 09:43:23 +00:00

add dismissable banner to the vault view when the active autofill tab is on the blocked domains list

This commit is contained in:
Jonathan Prusik
2024-11-15 17:09:46 -05:00
parent 5d60897f27
commit 2f8d2ac3cb
4 changed files with 65 additions and 3 deletions

View File

@@ -2339,6 +2339,12 @@
"blockedDomainsDesc": {
"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."
},
"autofillBlockedTooltip": {
"message": "Autofill is blocked on this website. Review in settings."
},
"websiteItemLabel": {
"message": "Website $number$ (URI)",
"placeholders": {

View File

@@ -22,6 +22,15 @@
</bit-no-items>
</div>
<bit-banner
*ngIf="vaultState !== VaultStateEnum.Empty && showScriptInjectionIsBlockedBanner"
id="domain-script-injection-blocked-banner"
bannerType="info"
(onClose)="handleScriptInjectionIsBlockedBannerDismiss()"
>
{{ "autofillBlockedNotice" | i18n }}
</bit-banner>
<!-- Show search & filters outside of the scroll area of the page -->
<ng-container
slot="above-scroll-area"

View File

@@ -3,18 +3,20 @@ import { CommonModule } from "@angular/common";
import { Component, OnDestroy, OnInit } from "@angular/core";
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
import { RouterLink } from "@angular/router";
import { combineLatest, Observable, shareReplay, switchMap } from "rxjs";
import { combineLatest, firstValueFrom, Observable, shareReplay, switchMap } from "rxjs";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { DomainSettingsService } from "@bitwarden/common/autofill/services/domain-settings.service";
import { CollectionId, OrganizationId } from "@bitwarden/common/types/guid";
import { CipherType } from "@bitwarden/common/vault/enums";
import { ButtonModule, Icons, NoItemsModule } from "@bitwarden/components";
import { BannerModule, ButtonModule, Icons, NoItemsModule } from "@bitwarden/components";
import { VaultIcons } from "@bitwarden/vault";
import { CurrentAccountComponent } from "../../../../auth/popup/account-switching/current-account.component";
import { PopOutComponent } from "../../../../platform/popup/components/pop-out.component";
import { PopupHeaderComponent } from "../../../../platform/popup/layout/popup-header.component";
import { PopupPageComponent } from "../../../../platform/popup/layout/popup-page.component";
import { VaultPopupAutofillService } from "../../services/vault-popup-autofill.service";
import { VaultPopupItemsService } from "../../services/vault-popup-items.service";
import { VaultPopupListFiltersService } from "../../services/vault-popup-list-filters.service";
import { VaultUiOnboardingService } from "../../services/vault-ui-onboarding.service";
@@ -45,6 +47,7 @@ enum VaultState {
CommonModule,
AutofillVaultListItemsComponent,
VaultListItemsContainerComponent,
BannerModule,
ButtonModule,
RouterLink,
NewItemDropdownV2Component,
@@ -59,6 +62,9 @@ export class VaultV2Component implements OnInit, OnDestroy {
protected favoriteCiphers$ = this.vaultPopupItemsService.favoriteCiphers$;
protected remainingCiphers$ = this.vaultPopupItemsService.remainingCiphers$;
protected loading$ = this.vaultPopupItemsService.loading$;
protected scriptInjectionIsBlocked = false;
protected showScriptInjectionIsBlockedBanner = false;
protected autofillTabHostname: string = null;
protected newItemItemValues$: Observable<NewItemInitialValues> =
this.vaultPopupListFiltersService.filters$.pipe(
@@ -86,6 +92,8 @@ export class VaultV2Component implements OnInit, OnDestroy {
constructor(
private vaultPopupItemsService: VaultPopupItemsService,
private vaultPopupListFiltersService: VaultPopupListFiltersService,
private domainSettingsService: DomainSettingsService,
private vaultPopupAutofillService: VaultPopupAutofillService,
private vaultUiOnboardingService: VaultUiOnboardingService,
) {
combineLatest([
@@ -110,6 +118,27 @@ export class VaultV2Component implements OnInit, OnDestroy {
this.vaultState = null;
}
});
combineLatest([
this.domainSettingsService.blockedInteractionsUris$,
this.vaultPopupAutofillService.currentAutofillTab$,
])
.pipe(takeUntilDestroyed())
.subscribe(([blockedInteractionsUris, currentAutofillTab]) => {
if (blockedInteractionsUris && currentAutofillTab?.url?.length) {
const autofillTabURL = new URL(currentAutofillTab.url);
this.autofillTabHostname = autofillTabURL.hostname;
const autofillTabIsBlocked = Object.keys(blockedInteractionsUris).includes(
autofillTabURL.hostname,
);
this.scriptInjectionIsBlocked = autofillTabIsBlocked;
this.showScriptInjectionIsBlockedBanner =
autofillTabIsBlocked &&
!blockedInteractionsUris[autofillTabURL.hostname]?.bannerIsDismissed;
}
});
}
async ngOnInit() {
@@ -117,4 +146,22 @@ export class VaultV2Component implements OnInit, OnDestroy {
}
ngOnDestroy(): void {}
handleScriptInjectionIsBlockedBannerDismiss() {
firstValueFrom(this.domainSettingsService.blockedInteractionsUris$)
.then((blockedURIs) => {
this.showScriptInjectionIsBlockedBanner = false;
this.domainSettingsService
.setBlockedInteractionsUris({
...blockedURIs,
[this.autofillTabHostname]: { bannerIsDismissed: true },
})
.catch(() => {
/* no-op */
});
})
.catch(() => {
/* no-op */
});
}
}

View File

@@ -21,5 +21,5 @@ export const UriMatchStrategy = {
export type UriMatchStrategySetting = (typeof UriMatchStrategy)[keyof typeof UriMatchStrategy];
// using uniqueness properties of object shape over Set for ease of state storability
export type NeverDomains = { [id: string]: null };
export type NeverDomains = { [id: string]: null | { bannerIsDismissed?: boolean } };
export type EquivalentDomains = string[][];