1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-11 13:53:34 +00:00

fix(routing): [PM-22995] update routing and tests (#15320)

Updates routing in 2 components to account for feature flag: `PM16117_SetInitialPasswordRefactor`
This commit is contained in:
rr-bw
2025-06-25 07:25:41 -07:00
committed by GitHub
parent ffd9072a98
commit 1b441e8a0f
3 changed files with 88 additions and 28 deletions

View File

@@ -23,10 +23,12 @@ import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
import { SsoPreValidateResponse } from "@bitwarden/common/auth/models/response/sso-pre-validate.response"; import { SsoPreValidateResponse } from "@bitwarden/common/auth/models/response/sso-pre-validate.response";
import { ClientType, HttpStatusCode } from "@bitwarden/common/enums"; import { ClientType, HttpStatusCode } from "@bitwarden/common/enums";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { CryptoFunctionService } from "@bitwarden/common/key-management/crypto/abstractions/crypto-function.service"; import { CryptoFunctionService } from "@bitwarden/common/key-management/crypto/abstractions/crypto-function.service";
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction";
import { ErrorResponse } from "@bitwarden/common/models/response/error.response"; import { ErrorResponse } from "@bitwarden/common/models/response/error.response";
import { ListResponse } from "@bitwarden/common/models/response/list.response"; import { ListResponse } from "@bitwarden/common/models/response/list.response";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
@@ -116,6 +118,7 @@ export class SsoComponent implements OnInit {
private toastService: ToastService, private toastService: ToastService,
private ssoComponentService: SsoComponentService, private ssoComponentService: SsoComponentService,
private loginSuccessHandlerService: LoginSuccessHandlerService, private loginSuccessHandlerService: LoginSuccessHandlerService,
private configService: ConfigService,
) { ) {
environmentService.environment$.pipe(takeUntilDestroyed()).subscribe((env) => { environmentService.environment$.pipe(takeUntilDestroyed()).subscribe((env) => {
this.redirectUri = env.getWebVaultUrl() + "/sso-connector.html"; this.redirectUri = env.getWebVaultUrl() + "/sso-connector.html";
@@ -531,7 +534,12 @@ export class SsoComponent implements OnInit {
} }
private async handleChangePasswordRequired(orgIdentifier: string) { private async handleChangePasswordRequired(orgIdentifier: string) {
await this.router.navigate(["set-password-jit"], { const isSetInitialPasswordRefactorFlagOn = await this.configService.getFeatureFlag(
FeatureFlag.PM16117_SetInitialPasswordRefactor,
);
const route = isSetInitialPasswordRefactorFlagOn ? "set-initial-password" : "set-password-jit";
await this.router.navigate([route], {
queryParams: { queryParams: {
identifier: orgIdentifier, identifier: orgIdentifier,
}, },

View File

@@ -27,6 +27,7 @@ import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/ide
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction";
import { FakeMasterPasswordService } from "@bitwarden/common/key-management/master-password/services/fake-master-password.service"; import { FakeMasterPasswordService } from "@bitwarden/common/key-management/master-password/services/fake-master-password.service";
import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
@@ -75,6 +76,7 @@ describe("TwoFactorAuthComponent", () => {
let mockLoginSuccessHandlerService: MockProxy<LoginSuccessHandlerService>; let mockLoginSuccessHandlerService: MockProxy<LoginSuccessHandlerService>;
let mockTwoFactorAuthCompCacheService: MockProxy<TwoFactorAuthComponentCacheService>; let mockTwoFactorAuthCompCacheService: MockProxy<TwoFactorAuthComponentCacheService>;
let mockAuthService: MockProxy<AuthService>; let mockAuthService: MockProxy<AuthService>;
let mockConfigService: MockProxy<ConfigService>;
let mockUserDecryptionOpts: { let mockUserDecryptionOpts: {
noMasterPassword: UserDecryptionOptions; noMasterPassword: UserDecryptionOptions;
@@ -110,6 +112,7 @@ describe("TwoFactorAuthComponent", () => {
mockToastService = mock<ToastService>(); mockToastService = mock<ToastService>();
mockTwoFactorAuthCompService = mock<TwoFactorAuthComponentService>(); mockTwoFactorAuthCompService = mock<TwoFactorAuthComponentService>();
mockAuthService = mock<AuthService>(); mockAuthService = mock<AuthService>();
mockConfigService = mock<ConfigService>();
mockEnvService = mock<EnvironmentService>(); mockEnvService = mock<EnvironmentService>();
mockLoginSuccessHandlerService = mock<LoginSuccessHandlerService>(); mockLoginSuccessHandlerService = mock<LoginSuccessHandlerService>();
@@ -209,6 +212,7 @@ describe("TwoFactorAuthComponent", () => {
useValue: mockTwoFactorAuthCompCacheService, useValue: mockTwoFactorAuthCompCacheService,
}, },
{ provide: AuthService, useValue: mockAuthService }, { provide: AuthService, useValue: mockAuthService },
{ provide: ConfigService, useValue: mockConfigService },
], ],
}); });
@@ -225,22 +229,6 @@ describe("TwoFactorAuthComponent", () => {
expect(component).toBeTruthy(); expect(component).toBeTruthy();
}); });
// Shared tests
const testChangePasswordOnSuccessfulLogin = () => {
it("navigates to the component's defined change password route when user doesn't have a MP and key connector isn't enabled", async () => {
// Act
await component.submit("testToken");
// Assert
expect(mockRouter.navigate).toHaveBeenCalledTimes(1);
expect(mockRouter.navigate).toHaveBeenCalledWith(["set-password"], {
queryParams: {
identifier: component.orgSsoIdentifier,
},
});
});
};
describe("Standard 2FA scenarios", () => { describe("Standard 2FA scenarios", () => {
describe("submit", () => { describe("submit", () => {
const token = "testToken"; const token = "testToken";
@@ -280,20 +268,76 @@ describe("TwoFactorAuthComponent", () => {
selectedUserDecryptionOptions.next(mockUserDecryptionOpts.noMasterPassword); selectedUserDecryptionOptions.next(mockUserDecryptionOpts.noMasterPassword);
}); });
testChangePasswordOnSuccessfulLogin(); describe("Given the PM16117_SetInitialPasswordRefactor feature flag is ON", () => {
it("navigates to the /set-initial-password route when user doesn't have a MP and key connector isn't enabled", async () => {
// Arrange
mockConfigService.getFeatureFlag.mockResolvedValue(true);
// Act
await component.submit("testToken");
// Assert
expect(mockRouter.navigate).toHaveBeenCalledTimes(1);
expect(mockRouter.navigate).toHaveBeenCalledWith(["set-initial-password"], {
queryParams: {
identifier: component.orgSsoIdentifier,
},
});
});
});
describe("Given the PM16117_SetInitialPasswordRefactor feature flag is OFF", () => {
it("navigates to the /set-password route when user doesn't have a MP and key connector isn't enabled", async () => {
// Arrange
mockConfigService.getFeatureFlag.mockResolvedValue(false);
// Act
await component.submit("testToken");
// Assert
expect(mockRouter.navigate).toHaveBeenCalledTimes(1);
expect(mockRouter.navigate).toHaveBeenCalledWith(["set-password"], {
queryParams: {
identifier: component.orgSsoIdentifier,
},
});
});
});
}); });
it("does not navigate to the change password route when the user has key connector even if user has no master password", async () => { describe("Given the PM16117_SetInitialPasswordRefactor feature flag is ON", () => {
selectedUserDecryptionOptions.next( it("does not navigate to the /set-initial-password route when the user has key connector even if user has no master password", async () => {
mockUserDecryptionOpts.noMasterPasswordWithKeyConnector, mockConfigService.getFeatureFlag.mockResolvedValue(true);
);
await component.submit(token, remember); selectedUserDecryptionOptions.next(
mockUserDecryptionOpts.noMasterPasswordWithKeyConnector,
);
expect(mockRouter.navigate).not.toHaveBeenCalledWith(["set-password"], { await component.submit(token, remember);
queryParams: {
identifier: component.orgSsoIdentifier, expect(mockRouter.navigate).not.toHaveBeenCalledWith(["set-initial-password"], {
}, queryParams: {
identifier: component.orgSsoIdentifier,
},
});
});
});
describe("Given the PM16117_SetInitialPasswordRefactor feature flag is OFF", () => {
it("does not navigate to the /set-password route when the user has key connector even if user has no master password", async () => {
mockConfigService.getFeatureFlag.mockResolvedValue(false);
selectedUserDecryptionOptions.next(
mockUserDecryptionOpts.noMasterPasswordWithKeyConnector,
);
await component.submit(token, remember);
expect(mockRouter.navigate).not.toHaveBeenCalledWith(["set-password"], {
queryParams: {
identifier: component.orgSsoIdentifier,
},
});
}); });
}); });
}); });

View File

@@ -32,7 +32,9 @@ import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-p
import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result"; import { AuthResult } from "@bitwarden/common/auth/models/domain/auth-result";
import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason"; import { ForceSetPasswordReason } from "@bitwarden/common/auth/models/domain/force-set-password-reason";
import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/identity-token/token-two-factor.request"; import { TokenTwoFactorRequest } from "@bitwarden/common/auth/models/request/identity-token/token-two-factor.request";
import { FeatureFlag } from "@bitwarden/common/enums/feature-flag.enum";
import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction"; import { InternalMasterPasswordServiceAbstraction } from "@bitwarden/common/key-management/master-password/abstractions/master-password.service.abstraction";
import { ConfigService } from "@bitwarden/common/platform/abstractions/config/config.service";
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service"; import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
@@ -169,6 +171,7 @@ export class TwoFactorAuthComponent implements OnInit, OnDestroy {
private loginSuccessHandlerService: LoginSuccessHandlerService, private loginSuccessHandlerService: LoginSuccessHandlerService,
private twoFactorAuthComponentCacheService: TwoFactorAuthComponentCacheService, private twoFactorAuthComponentCacheService: TwoFactorAuthComponentCacheService,
private authService: AuthService, private authService: AuthService,
private configService: ConfigService,
) {} ) {}
async ngOnInit() { async ngOnInit() {
@@ -559,7 +562,12 @@ export class TwoFactorAuthComponent implements OnInit, OnDestroy {
} }
private async handleChangePasswordRequired(orgIdentifier: string | undefined) { private async handleChangePasswordRequired(orgIdentifier: string | undefined) {
await this.router.navigate(["set-password"], { const isSetInitialPasswordRefactorFlagOn = await this.configService.getFeatureFlag(
FeatureFlag.PM16117_SetInitialPasswordRefactor,
);
const route = isSetInitialPasswordRefactorFlagOn ? "set-initial-password" : "set-password";
await this.router.navigate([route], {
queryParams: { queryParams: {
identifier: orgIdentifier, identifier: orgIdentifier,
}, },