Skip to content

Commit

Permalink
feat(auth): [PM-3953] generalize copy for login with device flows
Browse files Browse the repository at this point in the history
Updates UI text and translations for the login with device feature to be more consistent and clear across desktop, browser and web clients. Changes include:

- Updated titles and content for login via auth request components
- Revised translations for device approval modal
- Updated notification titles and alert messages
- Simplified device management URL handling
- Added missing translations across platforms

Resolves PM-3953
  • Loading branch information
alec-livefront authored Jan 31, 2025
1 parent 91509f2 commit 8e70d5b
Show file tree
Hide file tree
Showing 16 changed files with 146 additions and 57 deletions.
15 changes: 12 additions & 3 deletions apps/browser/src/_locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -3123,12 +3123,18 @@
"notificationSentDevice": {
"message": "A notification has been sent to your device."
},
"notificationSentDevicePart1": {
"message": "Unlock Bitwarden on your device or on the"
},
"notificationSentDeviceAnchor": {
"message": "web app"
},
"notificationSentDevicePart2": {
"message": "Make sure the Fingerprint phrase matches the one below before approving."
},
"aNotificationWasSentToYourDevice": {
"message": "A notification was sent to your device"
},
"makeSureYourAccountIsUnlockedAndTheFingerprintEtc": {
"message": "Make sure your account is unlocked and the fingerprint phrase matches on the other device"
},
"youWillBeNotifiedOnceTheRequestIsApproved": {
"message": "You will be notified once the request is approved"
},
Expand All @@ -3138,6 +3144,9 @@
"loginInitiated": {
"message": "Login initiated"
},
"logInRequestSent": {
"message": "Request sent"
},
"exposedMasterPassword": {
"message": "Exposed Master Password"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,20 @@ <h1 class="login-center">
<div class="content login-page">
<ng-container *ngIf="state == StateEnum.StandardAuthRequest">
<div>
<p class="lead">{{ "loginInitiated" | i18n }}</p>
<p class="lead">{{ "logInRequestSent" | i18n }}</p>

<div>
<p>{{ "notificationSentDevice" | i18n }}</p>

<p>
{{ "fingerprintMatchInfo" | i18n }}
{{ "notificationSentDevicePart1" | i18n }}
<a
bitLink
linkType="primary"
class="tw-cursor-pointer"
[href]="deviceManagementUrl"
target="_blank"
rel="noreferrer"
>{{ "notificationSentDeviceAnchor" | i18n }}</a
>. {{ "notificationSentDevicePart2" | i18n }}
</p>
</div>

Expand Down
2 changes: 1 addition & 1 deletion apps/browser/src/popup/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ const routes: Routes = [
data: {
pageIcon: DevicesIcon,
pageTitle: {
key: "loginInitiated",
key: "logInRequestSent",
},
pageSubtitle: {
key: "aNotificationWasSentToYourDevice",
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ const routes: Routes = [
data: {
pageIcon: DevicesIcon,
pageTitle: {
key: "loginInitiated",
key: "logInRequestSent",
},
pageSubtitle: {
key: "aNotificationWasSentToYourDevice",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,15 +51,15 @@ describe("DesktopLoginApprovalComponentService", () => {
it("calls ipc.auth.loginRequest with correct parameters when window is not visible", async () => {
const title = "Log in requested";
const email = "[email protected]";
const message = `Confirm login attempt for ${email}`;
const message = `Confirm access attempt for ${email}`;
const closeText = "Close";

const loginApprovalComponent = { email } as LoginApprovalComponent;
i18nService.t.mockImplementation((key: string) => {
switch (key) {
case "logInRequested":
case "accountAccessRequested":
return title;
case "confirmLoginAtemptForMail":
case "confirmAccessAttempt":
return message;
case "close":
return closeText;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// FIXME: Update this file to be type safe and remove this and next line
// @ts-strict-ignore
import { Injectable } from "@angular/core";

import { DefaultLoginApprovalComponentService } from "@bitwarden/auth/angular";
Expand All @@ -15,12 +13,12 @@ export class DesktopLoginApprovalComponentService
super();
}

async showLoginRequestedAlertIfWindowNotVisible(email: string): Promise<void> {
async showLoginRequestedAlertIfWindowNotVisible(email?: string): Promise<void> {
const isVisible = await ipc.platform.isWindowVisible();
if (!isVisible) {
await ipc.auth.loginRequest(
this.i18nService.t("logInRequested"),
this.i18nService.t("confirmLoginAtemptForMail", email),
this.i18nService.t("accountAccessRequested"),
this.i18nService.t("confirmAccessAttempt", email),
this.i18nService.t("close"),
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,23 @@
<img class="logo-image" alt="Bitwarden" />

<ng-container *ngIf="state == StateEnum.StandardAuthRequest">
<p class="lead text-center">{{ "loginInitiated" | i18n }}</p>
<p class="lead text-center">{{ "logInRequestSent" | i18n }}</p>

<div class="box last">
<div class="box-content">
<div class="box-content-row" appBoxRow>
<div class="section">
<p class="section">{{ "notificationSentDevice" | i18n }}</p>
<p>
{{ "fingerprintMatchInfo" | i18n }}
<p class="section">
{{ "notificationSentDevicePart1" | i18n }}
<a
bitLink
linkType="primary"
class="tw-cursor-pointer"
[href]="deviceManagementUrl"
target="_blank"
rel="noreferrer"
>{{ "notificationSentDeviceAnchor" | i18n }}</a
>. {{ "notificationSentDevicePart2" | i18n }}
</p>
</div>

Expand Down
36 changes: 24 additions & 12 deletions apps/desktop/src/locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -2745,14 +2745,23 @@
"loginInitiated": {
"message": "Login initiated"
},
"logInRequestSent": {
"message": "Request sent"
},
"notificationSentDevice": {
"message": "A notification has been sent to your device."
},
"aNotificationWasSentToYourDevice": {
"message": "A notification was sent to your device"
},
"makeSureYourAccountIsUnlockedAndTheFingerprintEtc": {
"message": "Make sure your account is unlocked and the fingerprint phrase matches on the other device"
"notificationSentDevicePart1": {
"message": "Unlock Bitwarden on your device or on the "
},
"notificationSentDeviceAnchor": {
"message": "web app"
},
"notificationSentDevicePart2": {
"message": "Make sure the Fingerprint phrase matches the one below before approving."
},
"needAnotherOptionV1": {
"message": "Need another option?"
Expand Down Expand Up @@ -2782,11 +2791,11 @@
"message": "Toggle character count",
"description": "'Character count' describes a feature that displays a number next to each character of the password."
},
"areYouTryingtoLogin": {
"message": "Are you trying to log in?"
"areYouTryingToAccessYourAccount": {
"message": "Are you trying to access your account?"
},
"logInAttemptBy": {
"message": "Login attempt by $EMAIL$",
"accessAttemptBy": {
"message": "Access attempt by $EMAIL$",
"placeholders": {
"email": {
"content": "$1",
Expand All @@ -2803,11 +2812,11 @@
"time": {
"message": "Time"
},
"confirmLogIn": {
"message": "Confirm login"
"confirmAccess": {
"message": "Confirm access"
},
"denyLogIn": {
"message": "Deny login"
"denyAccess": {
"message": "Deny access"
},
"logInConfirmedForEmailOnDevice": {
"message": "Login confirmed for $EMAIL$ on $DEVICE$",
Expand Down Expand Up @@ -2843,8 +2852,8 @@
"thisRequestIsNoLongerValid": {
"message": "This request is no longer valid."
},
"confirmLoginAtemptForMail": {
"message": "Confirm login attempt for $EMAIL$",
"confirmAccessAttempt": {
"message": "Confirm access attempt for $EMAIL$",
"placeholders": {
"email": {
"content": "$1",
Expand All @@ -2855,6 +2864,9 @@
"logInRequested": {
"message": "Log in requested"
},
"accountAccessRequested": {
"message": "Account access requested"
},
"creatingAccountOn": {
"message": "Creating account on"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
<!-- Please remove this disable statement when editing this file! -->
<!-- eslint-disable tailwindcss/no-custom-classname -->
<div
class="tw-mx-auto tw-mt-5 tw-flex tw-max-w-lg tw-flex-col tw-items-center tw-justify-center tw-p-8"
>
Expand All @@ -14,15 +12,11 @@
<div
class="tw-mt-3 tw-rounded-md tw-border tw-border-solid tw-border-secondary-300 tw-bg-background tw-p-6"
>
<h2 class="tw-mb-6 tw-text-xl tw-font-semibold">{{ "loginInitiated" | i18n }}</h2>
<h2 class="tw-mb-6 tw-text-xl tw-font-semibold">{{ "logInRequestSent" | i18n }}</h2>

<div class="tw-text-light">
<p class="tw-mb-6">{{ "notificationSentDevice" | i18n }}</p>

<p class="tw-mb-6">
{{ "fingerprintMatchInfo" | i18n }}
</p>
</div>
<p class="tw-mb-6">
{{ "notificationSentDeviceComplete" | i18n }}
</p>

<div class="tw-mb-6">
<h4 class="tw-font-semibold">{{ "fingerprintPhraseHeader" | i18n }}</h4>
Expand All @@ -39,7 +33,7 @@ <h4 class="tw-font-semibold">{{ "fingerprintPhraseHeader" | i18n }}</h4>

<hr />

<div class="tw-text-light tw-mt-3">
<div class="tw-mt-3">
{{ "loginWithDeviceEnabledNote" | i18n }}
<a routerLink="/login">{{ "viewAllLoginOptions" | i18n }}</a>
</div>
Expand All @@ -52,7 +46,7 @@ <h4 class="tw-font-semibold">{{ "fingerprintPhraseHeader" | i18n }}</h4>
>
<h2 class="tw-mb-6 tw-text-xl tw-font-semibold">{{ "adminApprovalRequested" | i18n }}</h2>

<div class="tw-text-light">
<div>
<p class="tw-mb-6">{{ "adminApprovalRequestSentToAdmins" | i18n }}</p>
<p class="tw-mb-6">{{ "youWillBeNotifiedOnceApproved" | i18n }}</p>
</div>
Expand All @@ -66,7 +60,7 @@ <h4 class="tw-font-semibold">{{ "fingerprintPhraseHeader" | i18n }}</h4>

<hr />

<div class="tw-text-light tw-mt-3">
<div class="tw-mt-3">
{{ "troubleLoggingIn" | i18n }}
<a routerLink="/login-initiated">{{ "viewAllLoginOptions" | i18n }}</a>
</div>
Expand Down
2 changes: 1 addition & 1 deletion apps/web/src/app/oss-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ const routes: Routes = [
data: {
pageIcon: DevicesIcon,
pageTitle: {
key: "loginInitiated",
key: "logInRequestSent",
},
pageSubtitle: {
key: "aNotificationWasSentToYourDevice",
Expand Down
36 changes: 33 additions & 3 deletions apps/web/src/locales/en/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -1203,6 +1203,9 @@
"logInInitiated": {
"message": "Log in initiated"
},
"logInRequestSent": {
"message": "Request sent"
},
"submit": {
"message": "Submit"
},
Expand Down Expand Up @@ -1392,12 +1395,39 @@
"notificationSentDevice": {
"message": "A notification has been sent to your device."
},
"notificationSentDevicePart1": {
"message": "Unlock Bitwarden on your device or on the "
},
"areYouTryingToAccessYourAccount": {
"message": "Are you trying to access your account?"
},
"accessAttemptBy": {
"message": "Access attempt by $EMAIL$",
"placeholders": {
"email": {
"content": "$1",
"example": "[email protected]"
}
}
},
"confirmAccess": {
"message": "Confirm access"
},
"denyAccess": {
"message": "Deny access"
},
"notificationSentDeviceAnchor": {
"message": "web app"
},
"notificationSentDevicePart2": {
"message": "Make sure the Fingerprint phrase matches the one below before approving."
},
"notificationSentDeviceComplete": {
"message": "Unlock Bitwarden on your device. Make sure the Fingerprint phrase matches the one below before approving."
},
"aNotificationWasSentToYourDevice": {
"message": "A notification was sent to your device"
},
"makeSureYourAccountIsUnlockedAndTheFingerprintEtc": {
"message": "Make sure your account is unlocked and the fingerprint phrase matches on the other device"
},
"versionNumber": {
"message": "Version $VERSION_NUMBER$",
"placeholders": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,12 @@ export class LoginViaAuthRequestComponentV1

protected StateEnum = State;
protected state = State.StandardAuthRequest;

protected webVaultUrl: string;
protected twoFactorRoute = "2fa";
protected successRoute = "vault";
protected forcePasswordResetRoute = "update-temp-password";
private resendTimeout = 12000;
protected deviceManagementUrl: string;

private authRequestKeyPair: { publicKey: Uint8Array; privateKey: Uint8Array };

Expand All @@ -95,6 +96,12 @@ export class LoginViaAuthRequestComponentV1
) {
super(environmentService, i18nService, platformUtilsService, toastService);

// Get the web vault URL from the environment service
environmentService.environment$.pipe(takeUntil(this.destroy$)).subscribe((env) => {
this.webVaultUrl = env.getWebVaultUrl();
this.deviceManagementUrl = `${this.webVaultUrl}/#/settings/security/device-management`;
});

// Gets signalR push notification
// Only fires on approval to prevent enumeration
this.authRequestService.authRequestPushNotification$
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<bit-dialog>
<span bitDialogTitle>{{ "areYouTryingtoLogin" | i18n }}</span>
<span bitDialogTitle>{{ "areYouTryingToAccessYourAccount" | i18n }}</span>
<ng-container bitDialogContent>
<ng-container *ngIf="loading">
<div class="tw-flex tw-items-center tw-justify-center" *ngIf="loading">
Expand All @@ -8,7 +8,7 @@
</ng-container>

<ng-container *ngIf="!loading">
<h4 class="tw-mb-3">{{ "logInAttemptBy" | i18n: email }}</h4>
<h4 class="tw-mb-3">{{ "accessAttemptBy" | i18n: email }}</h4>
<div>
<b>{{ "fingerprintPhraseHeader" | i18n }}</b>
<p class="tw-text-code">{{ fingerprintPhrase }}</p>
Expand All @@ -35,7 +35,7 @@ <h4 class="tw-mb-3">{{ "logInAttemptBy" | i18n: email }}</h4>
[bitAction]="approveLogin"
[disabled]="loading"
>
{{ "confirmLogIn" | i18n }}
{{ "confirmAccess" | i18n }}
</button>
<button
bitButton
Expand All @@ -44,7 +44,7 @@ <h4 class="tw-mb-3">{{ "logInAttemptBy" | i18n: email }}</h4>
[bitAction]="denyLogin"
[disabled]="loading"
>
{{ "denyLogIn" | i18n }}
{{ "denyAccess" | i18n }}
</button>
</ng-container>
</bit-dialog>
Loading

0 comments on commit 8e70d5b

Please sign in to comment.