mirror of
https://github.com/bitwarden/browser
synced 2025-12-15 15:53:27 +00:00
[PM-26649] Prevent log-out when changing KDF settings (except old clients) (#16775)
* Prevent log-out when changing KDF settings (except old clients) * test coverage * logout reason enum
This commit is contained in:
@@ -11,7 +11,7 @@ import { Matrix } from "../../../../spec/matrix";
|
||||
import { AccountService } from "../../../auth/abstractions/account.service";
|
||||
import { AuthService } from "../../../auth/abstractions/auth.service";
|
||||
import { AuthenticationStatus } from "../../../auth/enums/authentication-status";
|
||||
import { NotificationType } from "../../../enums";
|
||||
import { NotificationType, PushNotificationLogOutReasonType } from "../../../enums";
|
||||
import { NotificationResponse } from "../../../models/response/notification.response";
|
||||
import { UserId } from "../../../types/guid";
|
||||
import { AppIdService } from "../../abstractions/app-id.service";
|
||||
@@ -340,4 +340,56 @@ describe("NotificationsService", () => {
|
||||
expect(webPushNotificationConnectionService.supportStatus$).toHaveBeenCalledTimes(1);
|
||||
subscription.unsubscribe();
|
||||
});
|
||||
|
||||
describe("processNotification", () => {
|
||||
beforeEach(async () => {
|
||||
appIdService.getAppId.mockResolvedValue("test-app-id");
|
||||
activeAccount.next({ id: mockUser1, email: "email", name: "Test Name", emailVerified: true });
|
||||
});
|
||||
|
||||
describe("NotificationType.LogOut", () => {
|
||||
it.each([
|
||||
{ featureFlagEnabled: false, reason: undefined },
|
||||
{ featureFlagEnabled: true, reason: undefined },
|
||||
{ featureFlagEnabled: false, reason: PushNotificationLogOutReasonType.KdfChange },
|
||||
])(
|
||||
"should call logout callback when featureFlag=$featureFlagEnabled and reason=$reason",
|
||||
async ({ featureFlagEnabled, reason }) => {
|
||||
configService.getFeatureFlag$.mockReturnValue(of(featureFlagEnabled));
|
||||
|
||||
const payload: { UserId: UserId; Reason?: PushNotificationLogOutReasonType } = {
|
||||
UserId: mockUser1,
|
||||
Reason: undefined,
|
||||
};
|
||||
if (reason != null) {
|
||||
payload.Reason = reason;
|
||||
}
|
||||
|
||||
const notification = new NotificationResponse({
|
||||
type: NotificationType.LogOut,
|
||||
payload,
|
||||
contextId: "different-app-id",
|
||||
});
|
||||
|
||||
await sut["processNotification"](notification, mockUser1);
|
||||
|
||||
expect(logoutCallback).toHaveBeenCalledWith("logoutNotification", mockUser1);
|
||||
},
|
||||
);
|
||||
|
||||
it("should skip logout when receiving KDF change reason with feature flag enabled", async () => {
|
||||
configService.getFeatureFlag$.mockReturnValue(of(true));
|
||||
|
||||
const notification = new NotificationResponse({
|
||||
type: NotificationType.LogOut,
|
||||
payload: { UserId: mockUser1, Reason: PushNotificationLogOutReasonType.KdfChange },
|
||||
contextId: "different-app-id",
|
||||
});
|
||||
|
||||
await sut["processNotification"](notification, mockUser1);
|
||||
|
||||
expect(logoutCallback).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -22,8 +22,9 @@ import { trackedMerge } from "@bitwarden/common/platform/misc";
|
||||
import { AccountInfo, AccountService } from "../../../auth/abstractions/account.service";
|
||||
import { AuthService } from "../../../auth/abstractions/auth.service";
|
||||
import { AuthenticationStatus } from "../../../auth/enums/authentication-status";
|
||||
import { NotificationType } from "../../../enums";
|
||||
import { NotificationType, PushNotificationLogOutReasonType } from "../../../enums";
|
||||
import {
|
||||
LogOutNotification,
|
||||
NotificationResponse,
|
||||
SyncCipherNotification,
|
||||
SyncFolderNotification,
|
||||
@@ -263,10 +264,25 @@ export class DefaultServerNotificationsService implements ServerNotificationsSer
|
||||
this.activitySubject.next("inactive"); // Force a disconnect
|
||||
this.activitySubject.next("active"); // Allow a reconnect
|
||||
break;
|
||||
case NotificationType.LogOut:
|
||||
case NotificationType.LogOut: {
|
||||
this.logService.info("[Notifications Service] Received logout notification");
|
||||
await this.logoutCallback("logoutNotification", userId);
|
||||
|
||||
const logOutNotification = notification.payload as LogOutNotification;
|
||||
const noLogoutOnKdfChange = await firstValueFrom(
|
||||
this.configService.getFeatureFlag$(FeatureFlag.NoLogoutOnKdfChange),
|
||||
);
|
||||
if (
|
||||
noLogoutOnKdfChange &&
|
||||
logOutNotification.reason === PushNotificationLogOutReasonType.KdfChange
|
||||
) {
|
||||
this.logService.info(
|
||||
"[Notifications Service] Skipping logout due to no logout KDF change",
|
||||
);
|
||||
} else {
|
||||
await this.logoutCallback("logoutNotification", userId);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case NotificationType.SyncSendCreate:
|
||||
case NotificationType.SyncSendUpdate:
|
||||
await this.syncService.syncUpsertSend(
|
||||
|
||||
Reference in New Issue
Block a user