1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-10 21:33:27 +00:00

[PM-5718] Fix free organization generating TOTP (#11918)

* [PM-5718] Fix totp generation for free orgs in old add-edit component

* [PM-5718] Fix totp generation for free orgs in view cipher view component

* [PM-5718] Cleanup merge conflicts

* Don't generate totp code for premium users or free orgs

* Added redirect to organization helper page

* Changed text to learn more

* Only show upgrade message to premium users

* Show upgrade message to free users with free orgs as well

---------

Co-authored-by: Matt Bishop <mbishop@bitwarden.com>
Co-authored-by: gbubemismith <gsmithwalter@gmail.com>
This commit is contained in:
Shane Melton
2025-01-13 09:58:52 -08:00
committed by GitHub
parent 3bed613a91
commit 459fb1bcf4
9 changed files with 89 additions and 19 deletions

View File

@@ -116,7 +116,7 @@
<bit-label [appTextDrag]="totpCodeCopyObj?.totpCode"
>{{ "verificationCodeTotp" | i18n }}
<span
*ngIf="!(isPremium$ | async)"
*ngIf="!(allowTotpGeneration$ | async)"
bitBadge
variant="success"
class="tw-ml-2 tw-cursor-pointer"
@@ -130,14 +130,14 @@
id="totp"
readonly
bitInput
[type]="!(isPremium$ | async) ? 'password' : 'text'"
[type]="!(allowTotpGeneration$ | async) ? 'password' : 'text'"
[value]="totpCodeCopyObj?.totpCodeFormatted || '*** ***'"
aria-readonly="true"
data-testid="login-totp"
class="tw-font-mono"
/>
<div
*ngIf="isPremium$ | async"
*ngIf="allowTotpGeneration$ | async"
bitTotpCountdown
[cipher]="cipher"
bitSuffix
@@ -152,7 +152,7 @@
showToast
[appA11yTitle]="'copyVerificationCode' | i18n"
data-testid="copy-totp"
[disabled]="!(isPremium$ | async)"
[disabled]="!(allowTotpGeneration$ | async)"
class="disabled:tw-cursor-default"
></button>
</bit-form-field>

View File

@@ -2,7 +2,15 @@
// @ts-strict-ignore
import { CommonModule, DatePipe } from "@angular/common";
import { Component, inject, Input } from "@angular/core";
import { Observable, switchMap } from "rxjs";
import {
BehaviorSubject,
combineLatest,
filter,
map,
Observable,
shareReplay,
switchMap,
} from "rxjs";
import { JslibModule } from "@bitwarden/angular/jslib.module";
import { EventCollectionService } from "@bitwarden/common/abstractions/event/event-collection.service";
@@ -12,13 +20,13 @@ import { EventType } from "@bitwarden/common/enums";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
import { CipherView } from "@bitwarden/common/vault/models/view/cipher.view";
import {
BadgeModule,
ColorPasswordModule,
FormFieldModule,
IconButtonModule,
SectionComponent,
SectionHeaderComponent,
TypographyModule,
IconButtonModule,
BadgeModule,
ColorPasswordModule,
} from "@bitwarden/components";
// FIXME: remove `src` and fix import
@@ -51,13 +59,31 @@ type TotpCodeValues = {
],
})
export class LoginCredentialsViewComponent {
@Input() cipher: CipherView;
@Input()
get cipher(): CipherView {
return this._cipher$.value;
}
set cipher(value: CipherView) {
this._cipher$.next(value);
}
private _cipher$ = new BehaviorSubject<CipherView>(null);
isPremium$: Observable<boolean> = this.accountService.activeAccount$.pipe(
private _userHasPremium$: Observable<boolean> = this.accountService.activeAccount$.pipe(
switchMap((account) =>
this.billingAccountProfileStateService.hasPremiumFromAnySource$(account.id),
),
);
allowTotpGeneration$: Observable<boolean> = combineLatest([
this._userHasPremium$,
this._cipher$.pipe(filter((c) => c != null)),
]).pipe(
map(([userHasPremium, cipher]) => {
// User premium status only applies to personal ciphers, organizationUseTotp applies to organization ciphers
return (userHasPremium && cipher.organizationId == null) || cipher.organizationUseTotp;
}),
shareReplay({ refCount: true, bufferSize: 1 }),
);
showPasswordCount: boolean = false;
passwordRevealed: boolean = false;
totpCodeCopyObj: TotpCodeValues;