mirror of
https://github.com/bitwarden/browser.git
synced 2025-02-15 01:11:47 +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 { 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";
|
import { ZonedMessageListenerService } from "../../platform/browser/zoned-message-listener.service";
|
||||||
|
|
||||||
@ -11,7 +14,12 @@ interface Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class ExtensionTwoFactorAuthDuoComponentService implements TwoFactorAuthDuoComponentService {
|
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> {
|
listenForDuo2faResult$(): Observable<Duo2faResult> {
|
||||||
return this.browserMessagingApi.messageListener$().pipe(
|
return this.browserMessagingApi.messageListener$().pipe(
|
||||||
filter((msg: Message) => msg.command === "duoResult"),
|
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 { 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";
|
import { CommandDefinition, MessageListener } from "@bitwarden/common/platform/messaging";
|
||||||
|
|
||||||
// TODO: PM-16209 We should create a Duo2faMessageListenerService that listens for messages from duo
|
// 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 {
|
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> {
|
listenForDuo2faResult$(): Observable<Duo2faResult> {
|
||||||
return this.messageListener.messages$(DUO_2FA_RESULT_COMMAND).pipe(
|
return this.messageListener.messages$(DUO_2FA_RESULT_COMMAND).pipe(
|
||||||
map((msg) => {
|
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 { fromEvent, map, Observable, share } from "rxjs";
|
||||||
|
|
||||||
import { TwoFactorAuthDuoComponentService, Duo2faResult } from "@bitwarden/auth/angular";
|
import { TwoFactorAuthDuoComponentService, Duo2faResult } from "@bitwarden/auth/angular";
|
||||||
|
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||||
|
|
||||||
export class WebTwoFactorAuthDuoComponentService implements TwoFactorAuthDuoComponentService {
|
export class WebTwoFactorAuthDuoComponentService implements TwoFactorAuthDuoComponentService {
|
||||||
private duo2faResult$: Observable<Duo2faResult>;
|
private duo2faResult$: Observable<Duo2faResult>;
|
||||||
|
|
||||||
constructor() {
|
constructor(private platformUtilsService: PlatformUtilsService) {
|
||||||
const duoResultChannel: BroadcastChannel = new BroadcastChannel("duoResult");
|
const duoResultChannel: BroadcastChannel = new BroadcastChannel("duoResult");
|
||||||
|
|
||||||
this.duo2faResult$ = fromEvent(duoResultChannel, "message").pipe(
|
this.duo2faResult$ = fromEvent(duoResultChannel, "message").pipe(
|
||||||
@ -23,4 +24,8 @@ export class WebTwoFactorAuthDuoComponentService implements TwoFactorAuthDuoComp
|
|||||||
listenForDuo2faResult$(): Observable<Duo2faResult> {
|
listenForDuo2faResult$(): Observable<Duo2faResult> {
|
||||||
return this.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.
|
* @returns {Observable<Duo2faResult>} An observable that emits the result of the duo two-factor authentication process.
|
||||||
*/
|
*/
|
||||||
abstract listenForDuo2faResult$(): Observable<Duo2faResult>;
|
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 { DialogModule } from "@angular/cdk/dialog";
|
||||||
import { CommonModule } from "@angular/common";
|
import { CommonModule } from "@angular/common";
|
||||||
import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core";
|
import { Component, EventEmitter, Input, OnInit, Output } from "@angular/core";
|
||||||
|
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||||
import { ReactiveFormsModule, FormsModule } from "@angular/forms";
|
import { ReactiveFormsModule, FormsModule } from "@angular/forms";
|
||||||
|
|
||||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||||
@ -18,6 +19,11 @@ import {
|
|||||||
ToastService,
|
ToastService,
|
||||||
} from "@bitwarden/components";
|
} from "@bitwarden/components";
|
||||||
|
|
||||||
|
import {
|
||||||
|
Duo2faResult,
|
||||||
|
TwoFactorAuthDuoComponentService,
|
||||||
|
} from "./two-factor-auth-duo-component.service";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
standalone: true,
|
standalone: true,
|
||||||
selector: "app-two-factor-auth-duo",
|
selector: "app-two-factor-auth-duo",
|
||||||
@ -41,32 +47,27 @@ export class TwoFactorAuthDuoComponent implements OnInit {
|
|||||||
@Input() providerData: any;
|
@Input() providerData: any;
|
||||||
|
|
||||||
duoFramelessUrl: string = null;
|
duoFramelessUrl: string = null;
|
||||||
duoResultListenerInitialized = false;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
protected i18nService: I18nService,
|
protected i18nService: I18nService,
|
||||||
protected platformUtilsService: PlatformUtilsService,
|
protected platformUtilsService: PlatformUtilsService,
|
||||||
protected toastService: ToastService,
|
protected toastService: ToastService,
|
||||||
|
private twoFactorAuthDuoComponentService: TwoFactorAuthDuoComponentService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
async ngOnInit(): Promise<void> {
|
async ngOnInit(): Promise<void> {
|
||||||
await this.init();
|
this.twoFactorAuthDuoComponentService
|
||||||
}
|
.listenForDuo2faResult$()
|
||||||
|
.pipe(takeUntilDestroyed())
|
||||||
async init() {
|
.subscribe((duo2faResult: Duo2faResult) => {
|
||||||
// Setup listener for duo-redirect.ts connector to send back the code
|
this.token.emit(duo2faResult.token);
|
||||||
if (!this.duoResultListenerInitialized) {
|
});
|
||||||
// setup client specific duo result listener
|
|
||||||
this.setupDuoResultListener();
|
|
||||||
this.duoResultListenerInitialized = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// flow must be launched by user so they can choose to remember the device or not.
|
// flow must be launched by user so they can choose to remember the device or not.
|
||||||
this.duoFramelessUrl = this.providerData.AuthUrl;
|
this.duoFramelessUrl = this.providerData.AuthUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Each client will have own implementation
|
// Called via parent two-factor-auth component.
|
||||||
protected setupDuoResultListener(): void {}
|
|
||||||
async launchDuoFrameless(): Promise<void> {
|
async launchDuoFrameless(): Promise<void> {
|
||||||
if (this.duoFramelessUrl === null) {
|
if (this.duoFramelessUrl === null) {
|
||||||
this.toastService.showToast({
|
this.toastService.showToast({
|
||||||
@ -76,6 +77,7 @@ export class TwoFactorAuthDuoComponent implements OnInit {
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.platformUtilsService.launchUri(this.duoFramelessUrl);
|
|
||||||
|
await this.twoFactorAuthDuoComponentService.launchDuoFrameless(this.duoFramelessUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user