Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PM-8221] Route user to email OTP entry [clients] #12811

Open
wants to merge 35 commits into
base: main
Choose a base branch
from

Conversation

alec-livefront
Copy link
Collaborator

🎟️ Tracking

https://bitwarden.atlassian.net/browse/PM-8221?atlOrigin=eyJpIjoiOTdiY2RkOWIwYmFhNDUyMGI1MDA3MDM0M2ZkMGI1OTkiLCJwIjoiaiJ9

📔 Objective

Add an intermediate route (/device-verification) that requires a user to enter an OTP to proceed to the vault when they are attempting to log in on an unknown device.

📸 Screenshots

Web

GMT20250110-202812_Clip_Alec.Rippberger.s.Clip.01_10_2025.mp4

Desktop

GMT20250110-200921_Clip_Alec.Rippberger.s.Clip.01_10_2025.mp4

Browser Extension

GMT20250110-192642_Clip_Alec.Rippberger.s.Clip.01_10_2025.mp4

⏰ Reminders before review

  • Contributor guidelines followed
  • All formatters and local linters executed and passed
  • Written new unit and / or integration tests where applicable
  • Protected functional changes with optionality (feature flags)
  • Used internationalization (i18n) for all UI strings
  • CI builds passed
  • Communicated to DevOps any deployment requirements
  • Updated any necessary documentation (Confluence, contributing docs) or informed the documentation team

🦮 Reviewer guidelines

  • 👍 (:+1:) or similar for great changes
  • 📝 (:memo:) or ℹ️ (:information_source:) for notes or general info
  • ❓ (:question:) for questions
  • 🤔 (:thinking:) or 💭 (:thought_balloon:) for more open inquiry that's not quite a confirmed issue and could potentially benefit from discussion
  • 🎨 (:art:) for suggestions / improvements
  • ❌ (:x:) or ⚠️ (:warning:) for more significant problems or concerns needing attention
  • 🌱 (:seedling:) or ♻️ (:recycle:) for future improvements or indications of technical debt
  • ⛏ (:pick:) for minor or nitpick changes

alec-livefront and others added 27 commits December 27, 2024 16:24
…of processing (2) processDeviceVerificationResponse should cache data
… (2) Update form to use bitSubmit (3) Add todo for authenticating guard
Copy link
Contributor

github-actions bot commented Jan 10, 2025

Logo
Checkmarx One – Scan Summary & Detailsee8893fa-8724-4e9f-bf33-ca180c721a14

Fixed Issues (170)

Great job! The following issues were fixed in this Pull Request

Severity Issue Source File / Package
MEDIUM Client_Privacy_Violation /bitwarden_license/bit-web/src/app/tools/access-intelligence/org-at-risk-members-dialog.component.html: 17
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 467
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 103
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 103
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 103
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 103
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/desktop/src/vault/app/vault/view.component.html: 494
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 78
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 78
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 78
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 78
MEDIUM Client_Privacy_Violation /apps/browser/src/background/runtime.background.ts: 370
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 78
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 78
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 78
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 78
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 78
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 78
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 78
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 78
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 78
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 78
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 78
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 78
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 78
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 78
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 78
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 78
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 78
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 78
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 78
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 78
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 78
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 78
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 78
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 78
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 78
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 78
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 103
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 103
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 103
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 103
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 103
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 103
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 103
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 103
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 103
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 103
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 103
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 103
MEDIUM Client_Privacy_Violation /apps/web/src/app/vault/individual-vault/view.component.ts: 103

More results are available on the CxOne platform

@alec-livefront alec-livefront marked this pull request as ready for review January 10, 2025 22:46
@alec-livefront alec-livefront requested a review from a team as a code owner January 10, 2025 22:46
Copy link

codecov bot commented Jan 11, 2025

Codecov Report

Attention: Patch coverage is 19.37500% with 129 lines in your changes missing coverage. Please review.

Project coverage is 34.27%. Comparing base (b95080b) to head (ce10ca3).

✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...-verification/new-device-verification.component.ts 0.00% 55 Missing ⚠️
...ervices/login-strategies/login-strategy.service.ts 7.89% 33 Missing and 2 partials ⚠️
...auth/src/common/login-strategies/login.strategy.ts 38.09% 12 Missing and 1 partial ⚠️
...common/login-strategies/password-login.strategy.ts 14.28% 5 Missing and 1 partial ⚠️
libs/common/src/services/api.service.ts 0.00% 6 Missing ⚠️
libs/auth/src/angular/login/login.component.ts 0.00% 3 Missing ⚠️
...s/request/identity-token/password-token.request.ts 0.00% 3 Missing ⚠️
.../response/identity-device-verification.response.ts 40.00% 3 Missing ⚠️
...auth/src/angular/icons/device-verification.icon.ts 0.00% 2 Missing ⚠️
libs/angular/src/auth/guards/index.ts 0.00% 1 Missing ⚠️
... and 2 more
Additional details and impacted files
@@            Coverage Diff             @@
##             main   #12811      +/-   ##
==========================================
- Coverage   34.29%   34.27%   -0.03%     
==========================================
  Files        2934     2939       +5     
  Lines       90188    90329     +141     
  Branches    16939    16975      +36     
==========================================
+ Hits        30930    30957      +27     
- Misses      56794    56902     +108     
- Partials     2464     2470       +6     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link
Contributor

@JaredSnider-Bitwarden JaredSnider-Bitwarden left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking really nice! A few comments and requests for additional tests below:

@@ -236,6 +239,22 @@ const routes: Routes = [
],
},
),
{
path: "device-verification",
component: AnonLayoutWrapperComponent,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ : this should use the ExtensionAnonLayoutWrapperComponent with ExtensionAnonLayoutWrapperData. We should have a back button for the new page per Figma:
image

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[disabled]="formGroup.invalid"
>
{{ "continueLoggingIn" | i18n }}
</button>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 , since we have a back button or x on the extension, IOS, and Android, I wonder if we should have an explicit cancel button here as well for desktop and web (using the new device verification service to inform the component to show the button or not). Can you run that by product / design? Note: the bitwarden logo does take the user back to login so that might be deemed sufficient, but we do have a cancel on 2FA which is an comparable screen to this one.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❓ : is this still necessary after we updated the NewDeviceVerificationComponent to use the LoginStrategyService instead of the PasswordLoginStrategy directly?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice test suite!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for tackling the ts strict updates. Since this is the orchestrator of all login methods, please request a smoke test of all the touched strategies in the QA notes for this task.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❓ can we add tests for this please?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❓ can we add tests for this please?

* @param {IdentityDeviceVerificationResponse} response - The response from the server indicating that device verification is required.
* @returns {Promise<AuthResult>} - A promise that resolves to an AuthResult object
*/
protected async processDeviceVerificationResponse(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❓ can we add tests for this please?

.pipe(takeUntil(this.destroy$))
.subscribe((timedOut) => {
if (timedOut) {
this.logService.error("Session timed out.");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 , we probably should show a toast to the user in this scenario?

await this.router.navigate(["/update-temp-password"]);
return;
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❓ : We should for sure add a call to await this.syncService.fullSync(true); here.
However, can you investigate to see if we also need a call like this.loginEmailService.clearValues(); like 2FA has?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants