1
0
mirror of https://github.com/bitwarden/browser.git synced 2025-02-14 01:01:31 +01:00

PM-8113 - TwoFactorAuthDuoComponentService - define top level abstraction and each clients implementation of the duo2faResultListener

This commit is contained in:
Jared Snider 2024-12-18 17:20:59 -05:00
parent 1b660491ed
commit 9905c6fa0e
No known key found for this signature in database
GPG Key ID: A149DDD612516286
6 changed files with 104 additions and 0 deletions

View File

@ -0,0 +1,27 @@
import { filter, map, Observable } from "rxjs";
import { Duo2faResult, TwoFactorAuthDuoComponentService } from "@bitwarden/auth/angular";
import { ZonedMessageListenerService } from "../../platform/browser/zoned-message-listener.service";
interface Message {
command: string;
code: string;
state: string;
}
export class ExtensionTwoFactorAuthDuoComponentService implements TwoFactorAuthDuoComponentService {
constructor(private browserMessagingApi: ZonedMessageListenerService) {}
listenForDuo2faResult$(): Observable<Duo2faResult> {
return this.browserMessagingApi.messageListener$().pipe(
filter((msg: Message) => msg.command === "duoResult"),
map((msg: Message) => {
return {
code: msg.code,
state: msg.state,
token: `${msg.code}|${msg.state}`,
} as Duo2faResult;
}),
);
}
}

View File

@ -0,0 +1,28 @@
import { map, Observable } from "rxjs";
import { TwoFactorAuthDuoComponentService, Duo2faResult } from "@bitwarden/auth/angular";
import { CommandDefinition, MessageListener } from "@bitwarden/common/platform/messaging";
// TODO: PM-16209 We should create a Duo2faMessageListenerService that listens for messages from duo
// and this command definition should move to that file.
// We should explore consolidating the messaging approach across clients - i.e., we
// should use the same command definition across all clients. We use duoResult on extension for no real
// benefit.
export const DUO_2FA_RESULT_COMMAND = new CommandDefinition<{ code: string; state: string }>(
"duoCallback",
);
export class DesktopTwoFactorAuthDuoComponentService implements TwoFactorAuthDuoComponentService {
constructor(private messageListener: MessageListener) {}
listenForDuo2faResult$(): Observable<Duo2faResult> {
return this.messageListener.messages$(DUO_2FA_RESULT_COMMAND).pipe(
map((msg) => {
return {
code: msg.code,
state: msg.state,
token: `${msg.code}|${msg.state}`,
} as Duo2faResult;
}),
);
}
}

View File

@ -0,0 +1,26 @@
import { fromEvent, map, Observable, share } from "rxjs";
import { TwoFactorAuthDuoComponentService, Duo2faResult } from "@bitwarden/auth/angular";
export class WebTwoFactorAuthDuoComponentService implements TwoFactorAuthDuoComponentService {
private duo2faResult$: Observable<Duo2faResult>;
constructor() {
const duoResultChannel: BroadcastChannel = new BroadcastChannel("duoResult");
this.duo2faResult$ = fromEvent(duoResultChannel, "message").pipe(
map((msg: MessageEvent) => {
return {
code: msg.data.code,
state: msg.data.state,
token: `${msg.data.code}|${msg.data.state}`,
} as Duo2faResult;
}),
// share the observable so that multiple subscribers can listen to the same event
share(),
);
}
listenForDuo2faResult$(): Observable<Duo2faResult> {
return this.duo2faResult$;
}
}

View File

@ -1 +1,2 @@
export * from "./two-factor-auth-email";
export * from "./two-factor-auth-duo";

View File

@ -0,0 +1 @@
export * from "./two-factor-auth-duo-component.service";

View File

@ -0,0 +1,21 @@
import { Observable } from "rxjs";
export interface Duo2faResult {
code: string;
state: string;
/**
* The code and the state joined by a | character.
*/
token: string;
}
/**
* A service which manages all the cross client logic for the duo 2FA component.
*/
export abstract class TwoFactorAuthDuoComponentService {
/**
* Retrieves 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>;
}