1
0
mirror of https://github.com/bitwarden/browser synced 2026-01-21 11:53:34 +00:00

chore(feature-flags): Remove notification on inactive and locked user feature flags

This commit is contained in:
Todd Martin
2025-12-29 11:35:56 -05:00
committed by GitHub
parent e2a1cfcbe8
commit 146e2c0a12
3 changed files with 26 additions and 86 deletions

View File

@@ -70,8 +70,6 @@ export enum FeatureFlag {
/* Platform */
IpcChannelFramework = "ipc-channel-framework",
InactiveUserServerNotification = "pm-25130-receive-push-notifications-for-inactive-users",
PushNotificationsWhenLocked = "pm-19388-push-notifications-when-locked",
/* Innovation */
PM19148_InnovationArchive = "pm-19148-innovation-archive",
@@ -157,8 +155,6 @@ export const DefaultFeatureFlagValue = {
/* Platform */
[FeatureFlag.IpcChannelFramework]: FALSE,
[FeatureFlag.InactiveUserServerNotification]: FALSE,
[FeatureFlag.PushNotificationsWhenLocked]: FALSE,
/* Innovation */
[FeatureFlag.PM19148_InnovationArchive]: FALSE,

View File

@@ -5,7 +5,6 @@ import { BehaviorSubject, bufferCount, firstValueFrom, Subject, ObservedValueOf
import { LogoutReason } from "@bitwarden/auth/common";
import { InternalPolicyService } from "@bitwarden/common/admin-console/abstractions/policy/policy.service.abstraction";
import { AuthRequestAnsweringServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth-request-answering/auth-request-answering.service.abstraction";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { mockAccountInfoWith } from "../../../../spec";
import { AccountService } from "../../../auth/abstractions/account.service";
@@ -130,15 +129,6 @@ describe("DefaultServerNotificationsService (multi-user)", () => {
authRequestAnsweringService = mock<AuthRequestAnsweringServiceAbstraction>();
configService = mock<ConfigService>();
configService.getFeatureFlag$.mockImplementation((flag: FeatureFlag) => {
const flagValueByFlag: Partial<Record<FeatureFlag, boolean>> = {
[FeatureFlag.InactiveUserServerNotification]: true,
[FeatureFlag.PushNotificationsWhenLocked]: true,
};
return new BehaviorSubject(flagValueByFlag[flag] ?? false) as any;
});
policyService = mock<InternalPolicyService>();
defaultServerNotificationsService = new DefaultServerNotificationsService(

View File

@@ -71,48 +71,20 @@ export class DefaultServerNotificationsService implements ServerNotificationsSer
private readonly configService: ConfigService,
private readonly policyService: InternalPolicyService,
) {
this.notifications$ = this.configService
.getFeatureFlag$(FeatureFlag.InactiveUserServerNotification)
.pipe(
distinctUntilChanged(),
switchMap((inactiveUserServerNotificationEnabled) => {
if (inactiveUserServerNotificationEnabled) {
return this.accountService.accounts$.pipe(
map((accounts: Record<UserId, AccountInfo>): Set<UserId> => {
const validUserIds = Object.entries(accounts)
.filter(
([_, accountInfo]) => accountInfo.email !== "" || accountInfo.emailVerified,
)
.map(([userId, _]) => userId as UserId);
return new Set(validUserIds);
}),
trackedMerge((id: UserId) => {
return this.userNotifications$(id as UserId).pipe(
map(
(notification: NotificationResponse) => [notification, id as UserId] as const,
),
);
}),
);
}
return this.accountService.activeAccount$.pipe(
map((account) => account?.id),
distinctUntilChanged(),
switchMap((activeAccountId) => {
if (activeAccountId == null) {
// We don't emit server-notifications for inactive accounts currently
return EMPTY;
}
return this.userNotifications$(activeAccountId).pipe(
map((notification) => [notification, activeAccountId] as const),
);
}),
);
}),
share(), // Multiple subscribers should only create a single connection to the server
);
this.notifications$ = this.accountService.accounts$.pipe(
map((accounts: Record<UserId, AccountInfo>): Set<UserId> => {
const validUserIds = Object.entries(accounts)
.filter(([_, accountInfo]) => accountInfo.email !== "" || accountInfo.emailVerified)
.map(([userId, _]) => userId as UserId);
return new Set(validUserIds);
}),
trackedMerge((id: UserId) => {
return this.userNotifications$(id as UserId).pipe(
map((notification: NotificationResponse) => [notification, id as UserId] as const),
);
}),
share(), // Multiple subscribers should only create a single connection to the server
);
}
/**
@@ -175,25 +147,13 @@ export class DefaultServerNotificationsService implements ServerNotificationsSer
}
private hasAccessToken$(userId: UserId) {
return this.configService.getFeatureFlag$(FeatureFlag.PushNotificationsWhenLocked).pipe(
return this.authService.authStatusFor$(userId).pipe(
map(
(authStatus) =>
authStatus === AuthenticationStatus.Locked ||
authStatus === AuthenticationStatus.Unlocked,
),
distinctUntilChanged(),
switchMap((featureFlagEnabled) => {
if (featureFlagEnabled) {
return this.authService.authStatusFor$(userId).pipe(
map(
(authStatus) =>
authStatus === AuthenticationStatus.Locked ||
authStatus === AuthenticationStatus.Unlocked,
),
distinctUntilChanged(),
);
} else {
return this.authService.authStatusFor$(userId).pipe(
map((authStatus) => authStatus === AuthenticationStatus.Unlocked),
distinctUntilChanged(),
);
}
}),
);
}
@@ -208,19 +168,13 @@ export class DefaultServerNotificationsService implements ServerNotificationsSer
return;
}
if (
await firstValueFrom(
this.configService.getFeatureFlag$(FeatureFlag.InactiveUserServerNotification),
)
) {
const activeAccountId = await firstValueFrom(
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
);
const activeAccountId = await firstValueFrom(
this.accountService.activeAccount$.pipe(map((a) => a?.id)),
);
const isActiveUser = activeAccountId === userId;
if (!isActiveUser && !AllowedMultiUserNotificationTypes.has(notification.type)) {
return;
}
const notificationIsForActiveUser = activeAccountId === userId;
if (!notificationIsForActiveUser && !AllowedMultiUserNotificationTypes.has(notification.type)) {
return;
}
switch (notification.type) {