1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-23 11:43:46 +00:00
Files
browser/apps/web/src/app/auth/two-factor.component.html
Jared Snider c91ceb2014 Auth/PM-5368 & PM-4613 - Web & Browser - Add support for new 2FA Duo Frameless Redirect flow (#7670)
* [PM-5368] Open Duo auth url. Add BroadcastChannel listener for duo result.

* [PM-5368] Remove debug line. Use PlatformUtilService to launch Uri.

* PM-5368 - Some progress on getting new frameless duo implementation in place

* PM-5368 - Base2FAComp - Save off duoFramelessUrl for use later on as user must be given the option to remember the device before launching the duo frameless flow in the new tab.

* PM-5368 - Web - 2FA Comp - (1) Only show larger width when showing backwards compatible duo (2) Stack buttons per new design (3) selectedProviderType === providerType.OrganizationDuo is correct check for when org requires DUO

* PM-5368 - Web - 2FA Comp - translate duo stuff

* PM-4613 - Browser 2FA - Get most of DUO frameless in place. WIP. Must figure out how to transfer state from popup to popout + add popout logic to auth-popout-windows.ts. Converted existing useAnotherTwoStepMethod button to use new comp lib bitButton per design.

* PM-4613 - Browser 2FA Comp - (1) HTML - add margin around duo frameless text to match figma (2) Get popout extension logic working properly - now closes existing popup

* PM-4613 - TODO figure out communication between web and browser as broadcast channel will not work.

* PM-5368 - Base comp + web changes - (1)  Base component now has a setupDuoResultListener method for child classes to override (2) Web overrides setupDuoResultListener and cleans up broadcast channel once a duo result comes through.

* PM-4613 - Browser - (1) Add window message handling to content-message-handler content script to pass along the duo result message to the browser extension (2) 2FA comp - override setupDuoResultListener and use browserMessagingApi to listen to duoResult and submit when it comes through.

* PM-5368 - Web - 2FA comp - only clean up duo result channel on ngDestroy so that user can re-submit if an error occurs.

* PM-5368 and PM-4613 - (1) Update base 2FA comp to only initialize duo result listener once as init is called any time the user changes 2FA option if multiple are present (duo org and duo personal) (2) Each client now will only create a listener once even if it is called more than once (3) On web, only try to clean up the duoResultChannel if it was created to avoid erroring on other 2FA methods.

* PM-5368 - Base 2FA comp - add TODO to remove duo SDK handling once we remove the duo-redirect flag

* PM-5368 - Per PR feedback, avoid repetition of duo provider check by using a new public property for isDuoProvider

* PM-4613 -  Per PR feedback: (1) Deconstruct code out of data (2) Add test for duoResult.

---------

Co-authored-by: André Bispo <abispo@bitwarden.com>
2024-02-05 13:23:50 -05:00

175 lines
6.3 KiB
HTML

<form
#form
(ngSubmit)="submit()"
[appApiAction]="formPromise"
class="container"
ngNativeValidate
autocomplete="off"
>
<div class="row justify-content-md-center mt-5">
<div
class="col-5"
[ngClass]="{
'col-9': !duoFrameless && isDuoProvider
}"
>
<p class="lead text-center mb-4">{{ title }}</p>
<div class="card d-block">
<div class="card-body">
<ng-container
*ngIf="
selectedProviderType === providerType.Email ||
selectedProviderType === providerType.Authenticator
"
>
<p *ngIf="selectedProviderType === providerType.Authenticator">
{{ "enterVerificationCodeApp" | i18n }}
</p>
<p *ngIf="selectedProviderType === providerType.Email">
{{ "enterVerificationCodeEmail" | i18n: twoFactorEmail }}
</p>
<div class="form-group">
<label for="code" class="sr-only">{{ "verificationCode" | i18n }}</label>
<input
id="code"
type="text"
name="Code"
class="form-control"
[(ngModel)]="token"
required
appAutofocus
inputmode="tel"
appInputVerbatim
/>
<small class="form-text" *ngIf="selectedProviderType === providerType.Email">
<a
href="#"
appStopClick
(click)="sendEmail(true)"
[appApiAction]="emailPromise"
*ngIf="selectedProviderType === providerType.Email"
>
{{ "sendVerificationCodeEmailAgain" | i18n }}
</a>
</small>
</div>
</ng-container>
<ng-container *ngIf="selectedProviderType === providerType.Yubikey">
<p class="text-center">{{ "insertYubiKey" | i18n }}</p>
<picture>
<source srcset="../../images/yubikey.avif" type="image/avif" />
<source srcset="../../images/yubikey.webp" type="image/webp" />
<img src="../../images/yubikey.jpg" class="rounded img-fluid mb-3" alt="" />
</picture>
<div class="form-group">
<label for="code" class="sr-only">{{ "verificationCode" | i18n }}</label>
<input
id="code"
type="password"
name="Code"
class="form-control"
[(ngModel)]="token"
required
appAutofocus
appInputVerbatim
autocomplete="new-password"
/>
</div>
</ng-container>
<ng-container *ngIf="selectedProviderType === providerType.WebAuthn">
<div id="web-authn-frame" class="mb-3">
<iframe id="webauthn_iframe" sandbox="allow-scripts allow-same-origin"></iframe>
</div>
</ng-container>
<!-- Duo -->
<ng-container *ngIf="isDuoProvider">
<ng-container *ngIf="duoFrameless">
<p *ngIf="selectedProviderType === providerType.OrganizationDuo" class="tw-mb-0">
{{ "duoRequiredByOrgForAccount" | i18n }}
</p>
<p>{{ "launchDuoAndFollowStepsToFinishLoggingIn" | i18n }}</p>
</ng-container>
<ng-container *ngIf="!duoFrameless">
<div id="duo-frame" class="mb-3">
<iframe
id="duo_iframe"
sandbox="allow-scripts allow-forms allow-same-origin allow-popups allow-popups-to-escape-sandbox"
></iframe>
</div>
</ng-container>
</ng-container>
<i
class="bwi bwi-spinner text-muted bwi-spin pull-right"
title="{{ 'loading' | i18n }}"
*ngIf="form.loading && selectedProviderType === providerType.WebAuthn"
aria-hidden="true"
></i>
<div class="form-check" *ngIf="selectedProviderType != null">
<input
id="remember"
type="checkbox"
name="Remember"
class="form-check-input"
[(ngModel)]="remember"
/>
<label for="remember" class="form-check-label">{{ "rememberMe" | i18n }}</label>
</div>
<ng-container *ngIf="selectedProviderType == null">
<p>{{ "noTwoStepProviders" | i18n }}</p>
<p>{{ "noTwoStepProviders2" | i18n }}</p>
</ng-container>
<hr />
<div [hidden]="!showCaptcha()">
<iframe
id="hcaptcha_iframe"
height="80"
sandbox="allow-scripts allow-same-origin"
></iframe>
</div>
<!-- Buttons -->
<div class="tw-flex tw-flex-col tw-mb-3">
<button
type="submit"
class="btn btn-primary btn-block btn-submit"
[disabled]="form.loading"
*ngIf="
selectedProviderType != null &&
!isDuoProvider &&
selectedProviderType !== providerType.WebAuthn
"
>
<span>
<i class="bwi bwi-sign-in" aria-hidden="true"></i> {{ "continue" | i18n }}
</span>
<i
class="bwi bwi-spinner bwi-spin"
title="{{ 'loading' | i18n }}"
aria-hidden="true"
></i>
</button>
<button
(click)="launchDuoFrameless()"
type="button"
class="btn btn-primary btn-block"
[disabled]="form.loading"
*ngIf="duoFrameless && isDuoProvider"
>
<span> {{ "launchDuo" | i18n }} </span>
</button>
<a routerLink="/login" class="btn btn-outline-secondary btn-block">
{{ "cancel" | i18n }}
</a>
</div>
<div class="text-center">
<a href="#" appStopClick (click)="anotherMethod()">{{
"useAnotherTwoStepMethod" | i18n
}}</a>
</div>
</div>
</div>
</div>
</div>
</form>
<ng-template #twoFactorOptions></ng-template>