diff --git a/apps/browser/src/_locales/en/messages.json b/apps/browser/src/_locales/en/messages.json index 988c9b0a247..31b02def8a9 100644 --- a/apps/browser/src/_locales/en/messages.json +++ b/apps/browser/src/_locales/en/messages.json @@ -2696,10 +2696,10 @@ } }, "launchDuoAndFollowStepsToFinishLoggingIn": { - "message": "Launch DUO and follow the steps to finish logging in." + "message": "Launch Duo and follow the steps to finish logging in." }, "duoRequiredByOrgForAccount": { - "message": "DUO two-step login is required for your account." + "message": "Duo two-step login is required for your account." }, "openExtensionInNewWindowToCompleteLogin": { "message": "Open the extension in a new window to complete login" @@ -2708,7 +2708,7 @@ "message": "Popout extension" }, "launchDuo": { - "message": "Launch DUO" + "message": "Launch Duo" }, "importFormatError": { "message": "Data is not formatted correctly. Please check your import file and try again." diff --git a/apps/desktop/src/auth/two-factor.component.html b/apps/desktop/src/auth/two-factor.component.html index 44c4b1b60f6..afd866e1d54 100644 --- a/apps/desktop/src/auth/two-factor.component.html +++ b/apps/desktop/src/auth/two-factor.component.html @@ -1,157 +1,186 @@ -
-
-

{{ title }}

-

- {{ "enterVerificationCodeApp" | i18n }} -

-

- {{ "enterVerificationCodeEmail" | i18n: twoFactorEmail }} -

-
-
-
- +
+ +
+ Bitwarden +

{{ title }}

+ +
+ + +

+ {{ "enterVerificationCodeApp" | i18n }} +

+

+ {{ "enterVerificationCodeEmail" | i18n: twoFactorEmail }} +

+
+
+ + +
+
+ + + {{ "sendVerificationCodeEmailAgain" | i18n }} + + +
+ + + +

{{ "insertYubiKey" | i18n }}

+ + + + + +
+
+
+ + +
+
+
+
+ + + +
+
+ +
+
+
+ + + + +
+ + {{ "duoRequiredByOrgForAccount" | i18n }} + + {{ "launchDuoAndFollowStepsToFinishLoggingIn" | i18n }} +
+
+ + + +
+
+ +
+
+
+

{{ "noTwoStepProviders" | i18n }}

+

{{ "noTwoStepProviders2" | i18n }}

+
+
+
+ +
+
+
+ + +
+
+
+ + +
+ +
+ + +
+
+
-
- - +
+
-
-
- -

{{ "insertYubiKey" | i18n }}

- -
-
-
- - -
-
- - -
-
-
-
- -
- -
-
-
-
- - -
-
-
-
- -
- -
-
-
-
- - -
-
-
-
-
-
-
-

{{ "noTwoStepProviders" | i18n }}

-

{{ "noTwoStepProviders2" | i18n }}

-
-
-
-
-
-
- -
+
+ +
-
- - -
-
- - -
-
- + +
diff --git a/apps/desktop/src/auth/two-factor.component.ts b/apps/desktop/src/auth/two-factor.component.ts index 00cb7f52ac2..531e4fb13c7 100644 --- a/apps/desktop/src/auth/two-factor.component.ts +++ b/apps/desktop/src/auth/two-factor.component.ts @@ -1,4 +1,4 @@ -import { Component, Inject, ViewChild, ViewContainerRef } from "@angular/core"; +import { Component, Inject, NgZone, ViewChild, ViewContainerRef } from "@angular/core"; import { ActivatedRoute, Router } from "@angular/router"; import { TwoFactorComponent as BaseTwoFactorComponent } from "@bitwarden/angular/auth/components/two-factor.component"; @@ -11,6 +11,7 @@ import { SsoLoginServiceAbstraction } from "@bitwarden/common/auth/abstractions/ import { TwoFactorService } from "@bitwarden/common/auth/abstractions/two-factor.service"; import { TwoFactorProviderType } from "@bitwarden/common/auth/enums/two-factor-provider-type"; import { AppIdService } from "@bitwarden/common/platform/abstractions/app-id.service"; +import { BroadcasterService } from "@bitwarden/common/platform/abstractions/broadcaster.service"; import { ConfigServiceAbstraction } from "@bitwarden/common/platform/abstractions/config/config.service.abstraction"; import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; @@ -21,6 +22,8 @@ import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.serv import { TwoFactorOptionsComponent } from "./two-factor-options.component"; +const BroadcasterSubscriptionId = "TwoFactorComponent"; + @Component({ selector: "app-two-factor", templateUrl: "two-factor.component.html", @@ -31,6 +34,7 @@ export class TwoFactorComponent extends BaseTwoFactorComponent { twoFactorOptionsModal: ViewContainerRef; showingModal = false; + duoCallbackSubscriptionEnabled: boolean = false; constructor( loginStrategyService: LoginStrategyServiceAbstraction, @@ -40,8 +44,10 @@ export class TwoFactorComponent extends BaseTwoFactorComponent { platformUtilsService: PlatformUtilsService, syncService: SyncService, environmentService: EnvironmentService, + private broadcasterService: BroadcasterService, private modalService: ModalService, stateService: StateService, + private ngZone: NgZone, route: ActivatedRoute, logService: LogService, twoFactorService: TwoFactorService, @@ -115,4 +121,25 @@ export class TwoFactorComponent extends BaseTwoFactorComponent { content.setAttribute("style", "width:335px"); } } + + protected override setupDuoResultListener() { + if (!this.duoCallbackSubscriptionEnabled) { + this.broadcasterService.subscribe(BroadcasterSubscriptionId, async (message: any) => { + await this.ngZone.run(async () => { + if (message.command === "duoCallback") { + this.token = message.code; + await this.submit(); + } + }); + }); + this.duoCallbackSubscriptionEnabled = true; + } + } + + ngOnDestroy(): void { + if (this.duoCallbackSubscriptionEnabled) { + this.broadcasterService.unsubscribe(BroadcasterSubscriptionId); + this.duoCallbackSubscriptionEnabled = false; + } + } } diff --git a/apps/desktop/src/images/yubikey.avif b/apps/desktop/src/images/yubikey.avif new file mode 100644 index 00000000000..ca67e1a25cb Binary files /dev/null and b/apps/desktop/src/images/yubikey.avif differ diff --git a/apps/desktop/src/images/yubikey.webp b/apps/desktop/src/images/yubikey.webp new file mode 100644 index 00000000000..8d390876824 Binary files /dev/null and b/apps/desktop/src/images/yubikey.webp differ diff --git a/apps/desktop/src/locales/en/messages.json b/apps/desktop/src/locales/en/messages.json index 2319bc3e41d..d86d1773c92 100644 --- a/apps/desktop/src/locales/en/messages.json +++ b/apps/desktop/src/locales/en/messages.json @@ -2525,6 +2525,15 @@ } } }, + "launchDuoAndFollowStepsToFinishLoggingIn": { + "message": "Launch Duo and follow the steps to finish logging in." + }, + "duoRequiredByOrgForAccount": { + "message": "Duo two-step login is required for your account." + }, + "launchDuo": { + "message": "Launch Duo in Browser" + }, "importFormatError": { "message": "Data is not formatted correctly. Please check your import file and try again." }, diff --git a/apps/desktop/src/main.ts b/apps/desktop/src/main.ts index 6d4b2db19d0..d98bd88e0e4 100644 --- a/apps/desktop/src/main.ts +++ b/apps/desktop/src/main.ts @@ -277,15 +277,24 @@ export class Main { const url = new URL(s); const code = url.searchParams.get("code"); const receivedState = url.searchParams.get("state"); + let message = ""; - if (code == null || receivedState == null) { + if (code === null) { return; } - const message = - s.indexOf("bitwarden://import-callback-lp") === 0 - ? "importCallbackLastPass" - : "ssoCallback"; + if (s.indexOf("bitwarden://duo-callback") === 0) { + message = "duoCallback"; + } else if (receivedState === null) { + return; + } + + if (s.indexOf("bitwarden://import-callback-lp") === 0) { + message = "importCallbackLastPass"; + } else if (s.indexOf("bitwarden://sso-callback") === 0) { + message = "ssoCallback"; + } + this.messagingService.send(message, { code: code, state: receivedState }); }); } diff --git a/apps/web/src/locales/en/messages.json b/apps/web/src/locales/en/messages.json index b965a176ab0..f9bbd0031bf 100644 --- a/apps/web/src/locales/en/messages.json +++ b/apps/web/src/locales/en/messages.json @@ -5928,13 +5928,13 @@ } }, "launchDuoAndFollowStepsToFinishLoggingIn": { - "message": "Launch DUO and follow the steps to finish logging in." + "message": "Launch Duo and follow the steps to finish logging in." }, "duoRequiredByOrgForAccount": { - "message": "DUO two-step login is required for your account." + "message": "Duo two-step login is required for your account." }, "launchDuo": { - "message": "Launch DUO" + "message": "Launch Duo" }, "turnOn": { "message": "Turn on"