mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 16:23:44 +00:00
add BlockBrowserInjectionsByDomain feature flag and put feature behind it
This commit is contained in:
@@ -14,6 +14,7 @@ import {
|
|||||||
} from "@bitwarden/common/autofill/services/domain-settings.service";
|
} from "@bitwarden/common/autofill/services/domain-settings.service";
|
||||||
import { InlineMenuVisibilitySetting } from "@bitwarden/common/autofill/types";
|
import { InlineMenuVisibilitySetting } from "@bitwarden/common/autofill/types";
|
||||||
import { NeverDomains } from "@bitwarden/common/models/domain/domain-service";
|
import { NeverDomains } from "@bitwarden/common/models/domain/domain-service";
|
||||||
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
import {
|
import {
|
||||||
EnvironmentService,
|
EnvironmentService,
|
||||||
Region,
|
Region,
|
||||||
@@ -93,6 +94,7 @@ describe("OverlayBackground", () => {
|
|||||||
let logService: MockProxy<LogService>;
|
let logService: MockProxy<LogService>;
|
||||||
let cipherService: MockProxy<CipherService>;
|
let cipherService: MockProxy<CipherService>;
|
||||||
let autofillService: MockProxy<AutofillService>;
|
let autofillService: MockProxy<AutofillService>;
|
||||||
|
let configService: MockProxy<ConfigService>;
|
||||||
let activeAccountStatusMock$: BehaviorSubject<AuthenticationStatus>;
|
let activeAccountStatusMock$: BehaviorSubject<AuthenticationStatus>;
|
||||||
let authService: MockProxy<AuthService>;
|
let authService: MockProxy<AuthService>;
|
||||||
let environmentMock$: BehaviorSubject<CloudEnvironment>;
|
let environmentMock$: BehaviorSubject<CloudEnvironment>;
|
||||||
@@ -153,7 +155,7 @@ describe("OverlayBackground", () => {
|
|||||||
fakeStateProvider = new FakeStateProvider(accountService);
|
fakeStateProvider = new FakeStateProvider(accountService);
|
||||||
showFaviconsMock$ = new BehaviorSubject(true);
|
showFaviconsMock$ = new BehaviorSubject(true);
|
||||||
neverDomainsMock$ = new BehaviorSubject({});
|
neverDomainsMock$ = new BehaviorSubject({});
|
||||||
domainSettingsService = new DefaultDomainSettingsService(fakeStateProvider);
|
domainSettingsService = new DefaultDomainSettingsService(fakeStateProvider, configService);
|
||||||
domainSettingsService.showFavicons$ = showFaviconsMock$;
|
domainSettingsService.showFavicons$ = showFaviconsMock$;
|
||||||
domainSettingsService.neverDomains$ = neverDomainsMock$;
|
domainSettingsService.neverDomains$ = neverDomainsMock$;
|
||||||
logService = mock<LogService>();
|
logService = mock<LogService>();
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import {
|
|||||||
DefaultDomainSettingsService,
|
DefaultDomainSettingsService,
|
||||||
DomainSettingsService,
|
DomainSettingsService,
|
||||||
} from "@bitwarden/common/autofill/services/domain-settings.service";
|
} from "@bitwarden/common/autofill/services/domain-settings.service";
|
||||||
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
import {
|
import {
|
||||||
EnvironmentService,
|
EnvironmentService,
|
||||||
Region,
|
Region,
|
||||||
@@ -61,6 +62,7 @@ describe("OverlayBackground", () => {
|
|||||||
let overlayBackground: LegacyOverlayBackground;
|
let overlayBackground: LegacyOverlayBackground;
|
||||||
const cipherService = mock<CipherService>();
|
const cipherService = mock<CipherService>();
|
||||||
const autofillService = mock<AutofillService>();
|
const autofillService = mock<AutofillService>();
|
||||||
|
let configService: MockProxy<ConfigService>;
|
||||||
let activeAccountStatusMock$: BehaviorSubject<AuthenticationStatus>;
|
let activeAccountStatusMock$: BehaviorSubject<AuthenticationStatus>;
|
||||||
let authService: MockProxy<AuthService>;
|
let authService: MockProxy<AuthService>;
|
||||||
|
|
||||||
@@ -92,7 +94,7 @@ describe("OverlayBackground", () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
domainSettingsService = new DefaultDomainSettingsService(fakeStateProvider);
|
domainSettingsService = new DefaultDomainSettingsService(fakeStateProvider, configService);
|
||||||
activeAccountStatusMock$ = new BehaviorSubject(AuthenticationStatus.Unlocked);
|
activeAccountStatusMock$ = new BehaviorSubject(AuthenticationStatus.Unlocked);
|
||||||
authService = mock<AuthService>();
|
authService = mock<AuthService>();
|
||||||
authService.activeAccountStatus$ = activeAccountStatusMock$;
|
authService.activeAccountStatus$ = activeAccountStatusMock$;
|
||||||
|
|||||||
@@ -255,7 +255,7 @@
|
|||||||
{{ "showIdentitiesCurrentTabDesc" | i18n }}
|
{{ "showIdentitiesCurrentTabDesc" | i18n }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="box list">
|
<div class="box list" *ngIf="blockBrowserInjectionsByDomainEnabled">
|
||||||
<div class="box-content single-line">
|
<div class="box-content single-line">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ export class AutofillV1Component implements OnInit {
|
|||||||
protected autoFillOverlayVisibilityOptions: any[];
|
protected autoFillOverlayVisibilityOptions: any[];
|
||||||
protected disablePasswordManagerLink: string;
|
protected disablePasswordManagerLink: string;
|
||||||
protected inlineMenuPositioningImprovementsEnabled: boolean = false;
|
protected inlineMenuPositioningImprovementsEnabled: boolean = false;
|
||||||
|
protected blockBrowserInjectionsByDomainEnabled: boolean = false;
|
||||||
protected showInlineMenuIdentities: boolean = true;
|
protected showInlineMenuIdentities: boolean = true;
|
||||||
protected showInlineMenuCards: boolean = true;
|
protected showInlineMenuCards: boolean = true;
|
||||||
inlineMenuIsEnabled: boolean = false;
|
inlineMenuIsEnabled: boolean = false;
|
||||||
@@ -120,6 +121,10 @@ export class AutofillV1Component implements OnInit {
|
|||||||
FeatureFlag.InlineMenuPositioningImprovements,
|
FeatureFlag.InlineMenuPositioningImprovements,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.blockBrowserInjectionsByDomainEnabled = await this.configService.getFeatureFlag(
|
||||||
|
FeatureFlag.BlockBrowserInjectionsByDomain,
|
||||||
|
);
|
||||||
|
|
||||||
this.inlineMenuIsEnabled = this.isInlineMenuEnabled();
|
this.inlineMenuIsEnabled = this.isInlineMenuEnabled();
|
||||||
|
|
||||||
this.showInlineMenuIdentities =
|
this.showInlineMenuIdentities =
|
||||||
|
|||||||
@@ -282,7 +282,7 @@
|
|||||||
</bit-form-field>
|
</bit-form-field>
|
||||||
</bit-card>
|
</bit-card>
|
||||||
</bit-section>
|
</bit-section>
|
||||||
<bit-section>
|
<bit-section *ngIf="blockBrowserInjectionsByDomainEnabled">
|
||||||
<bit-item>
|
<bit-item>
|
||||||
<a bit-item-content routerLink="/blocked-domains">{{ "blockedDomains" | i18n }}</a>
|
<a bit-item-content routerLink="/blocked-domains">{{ "blockedDomains" | i18n }}</a>
|
||||||
<i slot="end" class="bwi bwi-angle-right bwi-lg row-sub-icon" aria-hidden="true"></i>
|
<i slot="end" class="bwi bwi-angle-right bwi-lg row-sub-icon" aria-hidden="true"></i>
|
||||||
|
|||||||
@@ -49,7 +49,6 @@ import {
|
|||||||
|
|
||||||
import { BrowserApi } from "../../../platform/browser/browser-api";
|
import { BrowserApi } from "../../../platform/browser/browser-api";
|
||||||
import { PopOutComponent } from "../../../platform/popup/components/pop-out.component";
|
import { PopOutComponent } from "../../../platform/popup/components/pop-out.component";
|
||||||
import { PopupFooterComponent } from "../../../platform/popup/layout/popup-footer.component";
|
|
||||||
import { PopupHeaderComponent } from "../../../platform/popup/layout/popup-header.component";
|
import { PopupHeaderComponent } from "../../../platform/popup/layout/popup-header.component";
|
||||||
import { PopupPageComponent } from "../../../platform/popup/layout/popup-page.component";
|
import { PopupPageComponent } from "../../../platform/popup/layout/popup-page.component";
|
||||||
|
|
||||||
@@ -67,7 +66,6 @@ import { PopupPageComponent } from "../../../platform/popup/layout/popup-page.co
|
|||||||
JslibModule,
|
JslibModule,
|
||||||
LinkModule,
|
LinkModule,
|
||||||
PopOutComponent,
|
PopOutComponent,
|
||||||
PopupFooterComponent,
|
|
||||||
PopupHeaderComponent,
|
PopupHeaderComponent,
|
||||||
PopupPageComponent,
|
PopupPageComponent,
|
||||||
RouterModule,
|
RouterModule,
|
||||||
@@ -87,6 +85,7 @@ export class AutofillComponent implements OnInit {
|
|||||||
protected inlineMenuVisibility: InlineMenuVisibilitySetting =
|
protected inlineMenuVisibility: InlineMenuVisibilitySetting =
|
||||||
AutofillOverlayVisibility.OnFieldFocus;
|
AutofillOverlayVisibility.OnFieldFocus;
|
||||||
protected inlineMenuPositioningImprovementsEnabled: boolean = false;
|
protected inlineMenuPositioningImprovementsEnabled: boolean = false;
|
||||||
|
protected blockBrowserInjectionsByDomainEnabled: boolean = false;
|
||||||
protected browserClientVendor: BrowserClientVendor = BrowserClientVendors.Unknown;
|
protected browserClientVendor: BrowserClientVendor = BrowserClientVendors.Unknown;
|
||||||
protected disablePasswordManagerURI: DisablePasswordManagerUri =
|
protected disablePasswordManagerURI: DisablePasswordManagerUri =
|
||||||
DisablePasswordManagerUris.Unknown;
|
DisablePasswordManagerUris.Unknown;
|
||||||
@@ -164,6 +163,10 @@ export class AutofillComponent implements OnInit {
|
|||||||
FeatureFlag.InlineMenuPositioningImprovements,
|
FeatureFlag.InlineMenuPositioningImprovements,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.blockBrowserInjectionsByDomainEnabled = await this.configService.getFeatureFlag(
|
||||||
|
FeatureFlag.BlockBrowserInjectionsByDomain,
|
||||||
|
);
|
||||||
|
|
||||||
this.showInlineMenuIdentities =
|
this.showInlineMenuIdentities =
|
||||||
this.inlineMenuPositioningImprovementsEnabled &&
|
this.inlineMenuPositioningImprovementsEnabled &&
|
||||||
(await firstValueFrom(this.autofillSettingsService.showInlineMenuIdentities$));
|
(await firstValueFrom(this.autofillSettingsService.showInlineMenuIdentities$));
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ describe("AutofillService", () => {
|
|||||||
userNotificationsSettings,
|
userNotificationsSettings,
|
||||||
messageListener,
|
messageListener,
|
||||||
);
|
);
|
||||||
domainSettingsService = new DefaultDomainSettingsService(fakeStateProvider);
|
domainSettingsService = new DefaultDomainSettingsService(fakeStateProvider, configService);
|
||||||
domainSettingsService.equivalentDomains$ = of(mockEquivalentDomains);
|
domainSettingsService.equivalentDomains$ = of(mockEquivalentDomains);
|
||||||
jest.spyOn(BrowserApi, "tabSendMessage");
|
jest.spyOn(BrowserApi, "tabSendMessage");
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -695,7 +695,6 @@ export default class MainBackground {
|
|||||||
this.vaultTimeoutSettingsService,
|
this.vaultTimeoutSettingsService,
|
||||||
);
|
);
|
||||||
|
|
||||||
this.domainSettingsService = new DefaultDomainSettingsService(this.stateProvider);
|
|
||||||
this.fileUploadService = new FileUploadService(this.logService, this.apiService);
|
this.fileUploadService = new FileUploadService(this.logService, this.apiService);
|
||||||
this.cipherFileUploadService = new CipherFileUploadService(
|
this.cipherFileUploadService = new CipherFileUploadService(
|
||||||
this.apiService,
|
this.apiService,
|
||||||
@@ -809,6 +808,11 @@ export default class MainBackground {
|
|||||||
this.authService,
|
this.authService,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.domainSettingsService = new DefaultDomainSettingsService(
|
||||||
|
this.stateProvider,
|
||||||
|
this.configService,
|
||||||
|
);
|
||||||
|
|
||||||
this.themeStateService = new DefaultThemeStateService(
|
this.themeStateService = new DefaultThemeStateService(
|
||||||
this.globalStateProvider,
|
this.globalStateProvider,
|
||||||
this.configService,
|
this.configService,
|
||||||
|
|||||||
@@ -327,7 +327,7 @@ const safeProviders: SafeProvider[] = [
|
|||||||
safeProvider({
|
safeProvider({
|
||||||
provide: DomainSettingsService,
|
provide: DomainSettingsService,
|
||||||
useClass: DefaultDomainSettingsService,
|
useClass: DefaultDomainSettingsService,
|
||||||
deps: [StateProvider],
|
deps: [StateProvider, ConfigService],
|
||||||
}),
|
}),
|
||||||
safeProvider({
|
safeProvider({
|
||||||
provide: AbstractStorageService,
|
provide: AbstractStorageService,
|
||||||
|
|||||||
@@ -1246,7 +1246,7 @@ const safeProviders: SafeProvider[] = [
|
|||||||
safeProvider({
|
safeProvider({
|
||||||
provide: DomainSettingsService,
|
provide: DomainSettingsService,
|
||||||
useClass: DefaultDomainSettingsService,
|
useClass: DefaultDomainSettingsService,
|
||||||
deps: [StateProvider],
|
deps: [StateProvider, ConfigService],
|
||||||
}),
|
}),
|
||||||
safeProvider({
|
safeProvider({
|
||||||
provide: BiometricStateService,
|
provide: BiometricStateService,
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
// FIXME: Update this file to be type safe and remove this and next line
|
// FIXME: Update this file to be type safe and remove this and next line
|
||||||
// @ts-strict-ignore
|
// @ts-strict-ignore
|
||||||
import { map, Observable } from "rxjs";
|
import { combineLatest, map, Observable } from "rxjs";
|
||||||
|
|
||||||
|
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
|
||||||
|
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
NeverDomains,
|
NeverDomains,
|
||||||
@@ -81,16 +84,30 @@ export class DefaultDomainSettingsService implements DomainSettingsService {
|
|||||||
private defaultUriMatchStrategyState: ActiveUserState<UriMatchStrategySetting>;
|
private defaultUriMatchStrategyState: ActiveUserState<UriMatchStrategySetting>;
|
||||||
readonly defaultUriMatchStrategy$: Observable<UriMatchStrategySetting>;
|
readonly defaultUriMatchStrategy$: Observable<UriMatchStrategySetting>;
|
||||||
|
|
||||||
constructor(private stateProvider: StateProvider) {
|
constructor(
|
||||||
|
private stateProvider: StateProvider,
|
||||||
|
private configService: ConfigService,
|
||||||
|
) {
|
||||||
this.showFaviconsState = this.stateProvider.getGlobal(SHOW_FAVICONS);
|
this.showFaviconsState = this.stateProvider.getGlobal(SHOW_FAVICONS);
|
||||||
this.showFavicons$ = this.showFaviconsState.state$.pipe(map((x) => x ?? true));
|
this.showFavicons$ = this.showFaviconsState.state$.pipe(map((x) => x ?? true));
|
||||||
|
|
||||||
this.neverDomainsState = this.stateProvider.getGlobal(NEVER_DOMAINS);
|
this.neverDomainsState = this.stateProvider.getGlobal(NEVER_DOMAINS);
|
||||||
this.neverDomains$ = this.neverDomainsState.state$.pipe(map((x) => x ?? null));
|
this.neverDomains$ = this.neverDomainsState.state$.pipe(map((x) => x ?? null));
|
||||||
|
|
||||||
|
// Needs to be global to prevent pre-login injections
|
||||||
this.blockedInteractionsUrisState = this.stateProvider.getGlobal(BLOCKED_INTERACTIONS_URIS);
|
this.blockedInteractionsUrisState = this.stateProvider.getGlobal(BLOCKED_INTERACTIONS_URIS);
|
||||||
this.blockedInteractionsUris$ = this.blockedInteractionsUrisState.state$.pipe(
|
|
||||||
map((x) => x ?? null),
|
this.blockedInteractionsUris$ = combineLatest([
|
||||||
|
this.blockedInteractionsUrisState.state$,
|
||||||
|
this.configService.getFeatureFlag$(FeatureFlag.BlockBrowserInjectionsByDomain),
|
||||||
|
]).pipe(
|
||||||
|
map(([blockedUris, blockBrowserInjectionsByDomainEnabled]) => {
|
||||||
|
if (!blockBrowserInjectionsByDomainEnabled) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return blockedUris ?? null;
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
this.equivalentDomainsState = this.stateProvider.getActive(EQUIVALENT_DOMAINS);
|
this.equivalentDomainsState = this.stateProvider.getActive(EQUIVALENT_DOMAINS);
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ export enum FeatureFlag {
|
|||||||
SSHKeyVaultItem = "ssh-key-vault-item",
|
SSHKeyVaultItem = "ssh-key-vault-item",
|
||||||
SSHAgent = "ssh-agent",
|
SSHAgent = "ssh-agent",
|
||||||
NotificationBarAddLoginImprovements = "notification-bar-add-login-improvements",
|
NotificationBarAddLoginImprovements = "notification-bar-add-login-improvements",
|
||||||
|
BlockBrowserInjectionsByDomain = "block-browser-injections-by-domain",
|
||||||
AC2476_DeprecateStripeSourcesAPI = "AC-2476-deprecate-stripe-sources-api",
|
AC2476_DeprecateStripeSourcesAPI = "AC-2476-deprecate-stripe-sources-api",
|
||||||
CipherKeyEncryption = "cipher-key-encryption",
|
CipherKeyEncryption = "cipher-key-encryption",
|
||||||
VerifiedSsoDomainEndpoint = "pm-12337-refactor-sso-details-endpoint",
|
VerifiedSsoDomainEndpoint = "pm-12337-refactor-sso-details-endpoint",
|
||||||
@@ -81,6 +82,7 @@ export const DefaultFeatureFlagValue = {
|
|||||||
[FeatureFlag.SSHKeyVaultItem]: FALSE,
|
[FeatureFlag.SSHKeyVaultItem]: FALSE,
|
||||||
[FeatureFlag.SSHAgent]: FALSE,
|
[FeatureFlag.SSHAgent]: FALSE,
|
||||||
[FeatureFlag.NotificationBarAddLoginImprovements]: FALSE,
|
[FeatureFlag.NotificationBarAddLoginImprovements]: FALSE,
|
||||||
|
[FeatureFlag.BlockBrowserInjectionsByDomain]: FALSE,
|
||||||
[FeatureFlag.AC2476_DeprecateStripeSourcesAPI]: FALSE,
|
[FeatureFlag.AC2476_DeprecateStripeSourcesAPI]: FALSE,
|
||||||
[FeatureFlag.CipherKeyEncryption]: FALSE,
|
[FeatureFlag.CipherKeyEncryption]: FALSE,
|
||||||
[FeatureFlag.VerifiedSsoDomainEndpoint]: FALSE,
|
[FeatureFlag.VerifiedSsoDomainEndpoint]: FALSE,
|
||||||
|
|||||||
Reference in New Issue
Block a user