mirror of
https://github.com/bitwarden/browser.git
synced 2025-02-15 01:11:47 +01:00
PM-8113 - TwoFactorAuthComponent - pull webauthn fallback response handling into primary init with checks based on client for if it should be processed.
This commit is contained in:
parent
831328c83c
commit
42719e4f13
@ -10,6 +10,10 @@ export class ExtensionTwoFactorAuthComponentService
|
||||
extends DefaultTwoFactorAuthComponentService
|
||||
implements TwoFactorAuthComponentService
|
||||
{
|
||||
shouldCheckForWebauthnResponseOnInit(): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
async handleSso2faFlowSuccess(): Promise<void> {
|
||||
// Force sidebars (FF && Opera) to reload while exempting current window
|
||||
// because we are just going to close the current window.
|
||||
|
@ -4,6 +4,10 @@ import {
|
||||
} from "./two-factor-auth-component.service";
|
||||
|
||||
export class DefaultTwoFactorAuthComponentService implements TwoFactorAuthComponentService {
|
||||
shouldCheckForWebauthnResponseOnInit() {
|
||||
return false;
|
||||
}
|
||||
|
||||
determineLegacyKeyMigrationAction() {
|
||||
return LegacyKeyMigrationAction.PREVENT_LOGIN_AND_SHOW_REQUIRE_MIGRATION_WARNING;
|
||||
}
|
||||
|
@ -8,6 +8,11 @@ export enum LegacyKeyMigrationAction {
|
||||
* implementation for all clients.
|
||||
*/
|
||||
export abstract class TwoFactorAuthComponentService {
|
||||
/**
|
||||
* Determines if the client should check for a webauthn response on init.
|
||||
* Currently, only the extension should check on init.
|
||||
*/
|
||||
abstract shouldCheckForWebauthnResponseOnInit(): boolean;
|
||||
/**
|
||||
* We used to use the user's master key to encrypt their data. We deprecated that approach
|
||||
* and now use a user key. This method should be called if we detect that the user
|
||||
|
@ -147,34 +147,44 @@ export class TwoFactorAuthComponent implements OnInit, OnDestroy {
|
||||
async ngOnInit() {
|
||||
this.inSsoFlow = this.activatedRoute.snapshot.queryParamMap.get("sso") === "true";
|
||||
this.orgSsoIdentifier = this.activatedRoute.snapshot.queryParamMap.get("identifier");
|
||||
this.listenFor2faSessionTimeout();
|
||||
|
||||
await this.determine2faProvider();
|
||||
await this.setTitleByTwoFactorProvider();
|
||||
if (this.twoFactorAuthComponentService.shouldCheckForWebauthnResponseOnInit()) {
|
||||
await this.processWebAuthnResponseIfExists();
|
||||
}
|
||||
|
||||
await this.setSelected2faProviderType();
|
||||
await this.set2faProviderData();
|
||||
await this.setTitleByTwoFactorProviderType();
|
||||
|
||||
this.form.valueChanges.pipe(takeUntilDestroyed()).subscribe((value) => {
|
||||
this.token = value.token;
|
||||
this.remember = value.remember;
|
||||
});
|
||||
|
||||
this.listenFor2faSessionTimeout();
|
||||
|
||||
// TODO: this is a temporary on init. Must genericize this and refactor out client specific stuff where possible.
|
||||
if (this.clientType === ClientType.Browser) {
|
||||
await this.extensionOnInit();
|
||||
}
|
||||
}
|
||||
|
||||
private async determine2faProvider() {
|
||||
private async processWebAuthnResponseIfExists() {
|
||||
const webAuthn2faResponse = this.activatedRoute.snapshot.queryParamMap.get("webAuthnResponse");
|
||||
if (webAuthn2faResponse) {
|
||||
this.selectedProviderType = TwoFactorProviderType.WebAuthn;
|
||||
await this.set2faProviderData();
|
||||
this.token = webAuthn2faResponse;
|
||||
this.remember = this.activatedRoute.snapshot.queryParamMap.get("remember") === "true";
|
||||
} else {
|
||||
const webAuthnSupported = this.platformUtilsService.supportsWebAuthn(this.win);
|
||||
this.selectedProviderType = await this.twoFactorService.getDefaultProvider(webAuthnSupported);
|
||||
await this.submit();
|
||||
}
|
||||
}
|
||||
|
||||
private async setSelected2faProviderType() {
|
||||
const webAuthnSupported = this.platformUtilsService.supportsWebAuthn(this.win);
|
||||
this.selectedProviderType = await this.twoFactorService.getDefaultProvider(webAuthnSupported);
|
||||
}
|
||||
|
||||
private async set2faProviderData() {
|
||||
const providerData = await this.twoFactorService.getProviders().then((providers) => {
|
||||
return providers.get(this.selectedProviderType);
|
||||
});
|
||||
@ -182,20 +192,6 @@ export class TwoFactorAuthComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
private async extensionOnInit() {
|
||||
if (this.activatedRoute.snapshot.paramMap.has("webAuthnResponse")) {
|
||||
// WebAuthn fallback response
|
||||
this.selectedProviderType = TwoFactorProviderType.WebAuthn;
|
||||
this.token = this.activatedRoute.snapshot.paramMap.get("webAuthnResponse");
|
||||
// TODO: move this to service.
|
||||
// this.onSuccessfulLogin = async () => {
|
||||
// this.messagingService.send("reloadPopup");
|
||||
// window.close();
|
||||
// };
|
||||
this.remember = this.activatedRoute.snapshot.paramMap.get("remember") === "true";
|
||||
await this.submit();
|
||||
return;
|
||||
}
|
||||
|
||||
// WebAuthn prompt appears inside the popup on linux, and requires a larger popup width
|
||||
// than usual to avoid cutting off the dialog.
|
||||
if (this.selectedProviderType === TwoFactorProviderType.WebAuthn && (await this.isLinux())) {
|
||||
@ -275,7 +271,7 @@ export class TwoFactorAuthComponent implements OnInit, OnDestroy {
|
||||
});
|
||||
this.providerData = providerData;
|
||||
this.selectedProviderType = response.type;
|
||||
await this.setTitleByTwoFactorProvider();
|
||||
await this.setTitleByTwoFactorProviderType();
|
||||
}
|
||||
}
|
||||
|
||||
@ -308,7 +304,7 @@ export class TwoFactorAuthComponent implements OnInit, OnDestroy {
|
||||
return true;
|
||||
}
|
||||
|
||||
async setTitleByTwoFactorProvider() {
|
||||
async setTitleByTwoFactorProviderType() {
|
||||
if (this.selectedProviderType == null) {
|
||||
this.title = this.i18nService.t("loginUnavailable");
|
||||
return;
|
||||
@ -368,6 +364,12 @@ export class TwoFactorAuthComponent implements OnInit, OnDestroy {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: test extension + webauthn 2fa to ensure these calls are no longer necessary:
|
||||
// this.onSuccessfulLogin = async () => {
|
||||
// this.messagingService.send("reloadPopup"); // this is just a navigate to "/"
|
||||
// window.close();
|
||||
// };
|
||||
|
||||
const defaultSuccessRoute = await this.determineDefaultSuccessRoute();
|
||||
|
||||
await this.router.navigate([defaultSuccessRoute], {
|
||||
|
Loading…
Reference in New Issue
Block a user