mirror of
https://github.com/bitwarden/browser.git
synced 2025-02-14 01:01:31 +01:00
PM-8113 - TwoFactorAuthDuoCompService - add client specific handling for launchDuoFrameless
This commit is contained in:
parent
9905c6fa0e
commit
5e9249a8cb
@ -1,6 +1,9 @@
|
||||
import { filter, map, Observable } from "rxjs";
|
||||
import { filter, firstValueFrom, map, Observable } from "rxjs";
|
||||
|
||||
import { Duo2faResult, TwoFactorAuthDuoComponentService } from "@bitwarden/auth/angular";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
|
||||
import { ZonedMessageListenerService } from "../../platform/browser/zoned-message-listener.service";
|
||||
|
||||
@ -11,7 +14,12 @@ interface Message {
|
||||
}
|
||||
|
||||
export class ExtensionTwoFactorAuthDuoComponentService implements TwoFactorAuthDuoComponentService {
|
||||
constructor(private browserMessagingApi: ZonedMessageListenerService) {}
|
||||
constructor(
|
||||
private browserMessagingApi: ZonedMessageListenerService,
|
||||
private environmentService: EnvironmentService,
|
||||
private i18nService: I18nService,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
) {}
|
||||
listenForDuo2faResult$(): Observable<Duo2faResult> {
|
||||
return this.browserMessagingApi.messageListener$().pipe(
|
||||
filter((msg: Message) => msg.command === "duoResult"),
|
||||
@ -24,4 +32,24 @@ export class ExtensionTwoFactorAuthDuoComponentService implements TwoFactorAuthD
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
async launchDuoFrameless(duoFramelessUrl: string): Promise<void> {
|
||||
const duoHandOffMessage = {
|
||||
title: this.i18nService.t("youSuccessfullyLoggedIn"),
|
||||
message: this.i18nService.t("youMayCloseThisWindow"),
|
||||
isCountdown: false,
|
||||
};
|
||||
|
||||
// we're using the connector here as a way to set a cookie with translations
|
||||
// before continuing to the duo frameless url
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
const launchUrl =
|
||||
env.getWebVaultUrl() +
|
||||
"/duo-redirect-connector.html" +
|
||||
"?duoFramelessUrl=" +
|
||||
encodeURIComponent(duoFramelessUrl) +
|
||||
"&handOffMessage=" +
|
||||
encodeURIComponent(JSON.stringify(duoHandOffMessage));
|
||||
this.platformUtilsService.launchUri(launchUrl);
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,9 @@
|
||||
import { map, Observable } from "rxjs";
|
||||
import { firstValueFrom, map, Observable } from "rxjs";
|
||||
|
||||
import { TwoFactorAuthDuoComponentService, Duo2faResult } from "@bitwarden/auth/angular";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { CommandDefinition, MessageListener } from "@bitwarden/common/platform/messaging";
|
||||
|
||||
// TODO: PM-16209 We should create a Duo2faMessageListenerService that listens for messages from duo
|
||||
@ -13,7 +16,12 @@ export const DUO_2FA_RESULT_COMMAND = new CommandDefinition<{ code: string; stat
|
||||
);
|
||||
|
||||
export class DesktopTwoFactorAuthDuoComponentService implements TwoFactorAuthDuoComponentService {
|
||||
constructor(private messageListener: MessageListener) {}
|
||||
constructor(
|
||||
private messageListener: MessageListener,
|
||||
private environmentService: EnvironmentService,
|
||||
private i18nService: I18nService,
|
||||
private platformUtilsService: PlatformUtilsService,
|
||||
) {}
|
||||
listenForDuo2faResult$(): Observable<Duo2faResult> {
|
||||
return this.messageListener.messages$(DUO_2FA_RESULT_COMMAND).pipe(
|
||||
map((msg) => {
|
||||
@ -25,4 +33,24 @@ export class DesktopTwoFactorAuthDuoComponentService implements TwoFactorAuthDuo
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
async launchDuoFrameless(duoFramelessUrl: string): Promise<void> {
|
||||
const duoHandOffMessage = {
|
||||
title: this.i18nService.t("youSuccessfullyLoggedIn"),
|
||||
message: this.i18nService.t("youMayCloseThisWindow"),
|
||||
isCountdown: false,
|
||||
};
|
||||
|
||||
// we're using the connector here as a way to set a cookie with translations
|
||||
// before continuing to the duo frameless url
|
||||
const env = await firstValueFrom(this.environmentService.environment$);
|
||||
const launchUrl =
|
||||
env.getWebVaultUrl() +
|
||||
"/duo-redirect-connector.html" +
|
||||
"?duoFramelessUrl=" +
|
||||
encodeURIComponent(duoFramelessUrl) +
|
||||
"&handOffMessage=" +
|
||||
encodeURIComponent(JSON.stringify(duoHandOffMessage));
|
||||
this.platformUtilsService.launchUri(launchUrl);
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
import { fromEvent, map, Observable, share } from "rxjs";
|
||||
|
||||
import { TwoFactorAuthDuoComponentService, Duo2faResult } from "@bitwarden/auth/angular";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
|
||||
export class WebTwoFactorAuthDuoComponentService implements TwoFactorAuthDuoComponentService {
|
||||
private duo2faResult$: Observable<Duo2faResult>;
|
||||
|
||||
constructor() {
|
||||
constructor(private platformUtilsService: PlatformUtilsService) {
|
||||
const duoResultChannel: BroadcastChannel = new BroadcastChannel("duoResult");
|
||||
|
||||
this.duo2faResult$ = fromEvent(duoResultChannel, "message").pipe(
|
||||
@ -23,4 +24,8 @@ export class WebTwoFactorAuthDuoComponentService implements TwoFactorAuthDuoComp
|
||||
listenForDuo2faResult$(): Observable<Duo2faResult> {
|
||||
return this.duo2faResult$;
|
||||
}
|
||||
|
||||
async launchDuoFrameless(duoFramelessUrl: string): Promise<void> {
|
||||
this.platformUtilsService.launchUri(duoFramelessUrl);
|
||||
}
|
||||
}
|
||||
|
@ -18,4 +18,9 @@ export abstract class TwoFactorAuthDuoComponentService {
|
||||
* @returns {Observable<Duo2faResult>} An observable that emits the result of the duo two-factor authentication process.
|
||||
*/
|
||||
abstract listenForDuo2faResult$(): Observable<Duo2faResult>;
|
||||
|
||||
/**
|
||||
* Launches the client specific duo frameless 2FA flow.
|
||||
*/
|
||||
abstract launchDuoFrameless(duoFramelessUrl: string): Promise<void>;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
import { DialogModule } from "@angular/cdk/dialog";
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core";
|
||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||
import { ReactiveFormsModule, FormsModule } from "@angular/forms";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
@ -18,6 +19,11 @@ import {
|
||||
ToastService,
|
||||
} from "@bitwarden/components";
|
||||
|
||||
import {
|
||||
Duo2faResult,
|
||||
TwoFactorAuthDuoComponentService,
|
||||
} from "./two-factor-auth-duo-component.service";
|
||||
|
||||
@Component({
|
||||
standalone: true,
|
||||
selector: "app-two-factor-auth-duo",
|
||||
@ -41,32 +47,27 @@ export class TwoFactorAuthDuoComponent implements OnInit {
|
||||
@Input() providerData: any;
|
||||
|
||||
duoFramelessUrl: string = null;
|
||||
duoResultListenerInitialized = false;
|
||||
|
||||
constructor(
|
||||
protected i18nService: I18nService,
|
||||
protected platformUtilsService: PlatformUtilsService,
|
||||
protected toastService: ToastService,
|
||||
private twoFactorAuthDuoComponentService: TwoFactorAuthDuoComponentService,
|
||||
) {}
|
||||
|
||||
async ngOnInit(): Promise<void> {
|
||||
await this.init();
|
||||
}
|
||||
|
||||
async init() {
|
||||
// Setup listener for duo-redirect.ts connector to send back the code
|
||||
if (!this.duoResultListenerInitialized) {
|
||||
// setup client specific duo result listener
|
||||
this.setupDuoResultListener();
|
||||
this.duoResultListenerInitialized = true;
|
||||
}
|
||||
this.twoFactorAuthDuoComponentService
|
||||
.listenForDuo2faResult$()
|
||||
.pipe(takeUntilDestroyed())
|
||||
.subscribe((duo2faResult: Duo2faResult) => {
|
||||
this.token.emit(duo2faResult.token);
|
||||
});
|
||||
|
||||
// flow must be launched by user so they can choose to remember the device or not.
|
||||
this.duoFramelessUrl = this.providerData.AuthUrl;
|
||||
}
|
||||
|
||||
// Each client will have own implementation
|
||||
protected setupDuoResultListener(): void {}
|
||||
// Called via parent two-factor-auth component.
|
||||
async launchDuoFrameless(): Promise<void> {
|
||||
if (this.duoFramelessUrl === null) {
|
||||
this.toastService.showToast({
|
||||
@ -76,6 +77,7 @@ export class TwoFactorAuthDuoComponent implements OnInit {
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.platformUtilsService.launchUri(this.duoFramelessUrl);
|
||||
|
||||
await this.twoFactorAuthDuoComponentService.launchDuoFrameless(this.duoFramelessUrl);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user