mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 08:13:42 +00:00
[SG-416] Updates to Bitwarden Authenticator (#3045)
* [SG-416] Changed UI for TOTP codes on free plan and added link to get Premium. On browser, changed back action of premium.component in order to reuse on cipher details. * [SSG-416] PR Fix * [SSG-416] fix formatting * [SSG-416] Updated desktop free plan OTP UI * [SSG-416] noticed a bad div tag making file changes erratic * [SG-416] fixed label * [SSG-416] Fix formatting * [SSG-416] Changed bootstrap classes to tailwind * [SSG-416] Added premium and upgrade badge back. Muted placeholder totp code colors and button. * [SSG-416] Change learn more to upgrade label on get premium modal. Fixed navigation for premium. * [SSG-416] Removed unused image file. * [SG-416] Changed browser "Premium subscription required" text to be all hyperlink. * [SG-416] Fixed missing resource on browser * [SG-416] Code format with lint
This commit is contained in:
committed by
GitHub
parent
31cae4390f
commit
c4f9c2cca6
@@ -1968,6 +1968,9 @@
|
|||||||
"ssoKeyConnectorError": {
|
"ssoKeyConnectorError": {
|
||||||
"message": "Key Connector error: make sure Key Connector is available and working correctly."
|
"message": "Key Connector error: make sure Key Connector is available and working correctly."
|
||||||
},
|
},
|
||||||
|
"premiumSubcriptionRequired": {
|
||||||
|
"message": "Premium subscription required"
|
||||||
|
},
|
||||||
"organizationIsDisabled": {
|
"organizationIsDisabled": {
|
||||||
"message": "Organization is disabled."
|
"message": "Organization is disabled."
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<header>
|
<header>
|
||||||
<div class="left">
|
<div class="left">
|
||||||
<button type="button" routerLink="/tabs/settings">
|
<button type="button" (click)="goBack()">
|
||||||
<span class="header-icon"><i class="bwi bwi-angle-left" aria-hidden="true"></i></span>
|
<span class="header-icon"><i class="bwi bwi-angle-left" aria-hidden="true"></i></span>
|
||||||
<span>{{ "back" | i18n }}</span>
|
<span>{{ "back" | i18n }}</span>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { CurrencyPipe } from "@angular/common";
|
import { CurrencyPipe, Location } from "@angular/common";
|
||||||
import { Component } from "@angular/core";
|
import { Component } from "@angular/core";
|
||||||
|
|
||||||
import { PremiumComponent as BasePremiumComponent } from "@bitwarden/angular/components/premium.component";
|
import { PremiumComponent as BasePremiumComponent } from "@bitwarden/angular/components/premium.component";
|
||||||
@@ -21,6 +21,7 @@ export class PremiumComponent extends BasePremiumComponent {
|
|||||||
apiService: ApiService,
|
apiService: ApiService,
|
||||||
stateService: StateService,
|
stateService: StateService,
|
||||||
logService: LogService,
|
logService: LogService,
|
||||||
|
private location: Location,
|
||||||
private currencyPipe: CurrencyPipe
|
private currencyPipe: CurrencyPipe
|
||||||
) {
|
) {
|
||||||
super(i18nService, platformUtilsService, apiService, logService, stateService);
|
super(i18nService, platformUtilsService, apiService, logService, stateService);
|
||||||
@@ -32,4 +33,8 @@ export class PremiumComponent extends BasePremiumComponent {
|
|||||||
this.priceString = this.priceString.replace("%price%", thePrice);
|
this.priceString = this.priceString.replace("%price%", thePrice);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
goBack() {
|
||||||
|
this.location.back();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -139,7 +139,7 @@
|
|||||||
<div
|
<div
|
||||||
class="box-content-row box-content-row-flex totp"
|
class="box-content-row box-content-row-flex totp"
|
||||||
[ngClass]="{ low: totpLow }"
|
[ngClass]="{ low: totpLow }"
|
||||||
*ngIf="cipher.login.totp && totpCode"
|
*ngIf="cipher.login.totp && totpCode && canAccessPremium"
|
||||||
>
|
>
|
||||||
<div class="row-main">
|
<div class="row-main">
|
||||||
<span
|
<span
|
||||||
@@ -177,6 +177,20 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="box-content-row box-content-row-flex totp"
|
||||||
|
*ngIf="cipher.login.totp && !canAccessPremium"
|
||||||
|
>
|
||||||
|
<div class="row-main">
|
||||||
|
<span class="row-label">{{ "verificationCodeTotp" | i18n }}</span>
|
||||||
|
<span class="row-label">
|
||||||
|
<a routerLink="/premium">
|
||||||
|
{{ "premiumSubcriptionRequired" | i18n }}
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Card -->
|
<!-- Card -->
|
||||||
<div *ngIf="cipher.card">
|
<div *ngIf="cipher.card">
|
||||||
|
|||||||
@@ -100,7 +100,7 @@
|
|||||||
<div
|
<div
|
||||||
class="box-content-row box-content-row-flex totp"
|
class="box-content-row box-content-row-flex totp"
|
||||||
[ngClass]="{ low: totpLow }"
|
[ngClass]="{ low: totpLow }"
|
||||||
*ngIf="cipher.login.totp && totpCode"
|
*ngIf="cipher.login.totp && totpCode && canAccessPremium"
|
||||||
>
|
>
|
||||||
<div class="row-main">
|
<div class="row-main">
|
||||||
<span
|
<span
|
||||||
@@ -138,6 +138,19 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div
|
||||||
|
class="box-content-row box-content-row-flex totp"
|
||||||
|
*ngIf="cipher.login.totp && !canAccessPremium"
|
||||||
|
>
|
||||||
|
<div class="row-main">
|
||||||
|
<span class="row-label">{{ "verificationCodeTotp" | i18n }}</span>
|
||||||
|
<span class="row-label">
|
||||||
|
<a [routerLink]="" (click)="showGetPremium()"
|
||||||
|
>{{ "premiumSubcriptionRequired" | i18n }}
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<!-- Card -->
|
<!-- Card -->
|
||||||
<div *ngIf="cipher.card">
|
<div *ngIf="cipher.card">
|
||||||
|
|||||||
@@ -115,4 +115,10 @@ export class ViewComponent extends BaseViewComponent implements OnChanges {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showGetPremium() {
|
||||||
|
if (!this.canAccessPremium) {
|
||||||
|
this.messagingService.send("premiumRequired");
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1979,6 +1979,9 @@
|
|||||||
"apiKey": {
|
"apiKey": {
|
||||||
"message": "API Key"
|
"message": "API Key"
|
||||||
},
|
},
|
||||||
|
"premiumSubcriptionRequired": {
|
||||||
|
"message": "Premium subscription required"
|
||||||
|
},
|
||||||
"organizationIsDisabled": {
|
"organizationIsDisabled": {
|
||||||
"message": "Organization is disabled."
|
"message": "Organization is disabled."
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ export class AppComponent implements OnDestroy, OnInit {
|
|||||||
const premiumConfirmed = await this.platformUtilsService.showDialog(
|
const premiumConfirmed = await this.platformUtilsService.showDialog(
|
||||||
this.i18nService.t("premiumRequiredDesc"),
|
this.i18nService.t("premiumRequiredDesc"),
|
||||||
this.i18nService.t("premiumRequired"),
|
this.i18nService.t("premiumRequired"),
|
||||||
this.i18nService.t("learnMore"),
|
this.i18nService.t("upgrade"),
|
||||||
this.i18nService.t("cancel")
|
this.i18nService.t("cancel")
|
||||||
);
|
);
|
||||||
if (premiumConfirmed) {
|
if (premiumConfirmed) {
|
||||||
|
|||||||
@@ -166,8 +166,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="tw-flex tw-flex-row">
|
||||||
<div class="col-6 form-group">
|
<div class="tw-mb-4 tw-w-1/2">
|
||||||
<label for="loginTotp">{{ "authenticatorKeyTotp" | i18n }}</label>
|
<label for="loginTotp">{{ "authenticatorKeyTotp" | i18n }}</label>
|
||||||
<input
|
<input
|
||||||
id="loginTotp"
|
id="loginTotp"
|
||||||
@@ -179,14 +179,41 @@
|
|||||||
[disabled]="cipher.isDeleted || !cipher.viewPassword || viewOnly"
|
[disabled]="cipher.isDeleted || !cipher.viewPassword || viewOnly"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-6 form-group totp d-flex align-items-end" [ngClass]="{ low: totpLow }">
|
<div class="tw-mb-4 tw-ml-4 tw-flex tw-w-1/2 tw-items-end" [ngClass]="{ low: totpLow }">
|
||||||
<div *ngIf="!cipher.login.totp || !totpCode">
|
<div
|
||||||
<img
|
class="totp tw-flex tw-flex-row tw-items-center"
|
||||||
src="../../images/totp-countdown.png"
|
*ngIf="!cipher.login.totp || (cipher.login.totp && !canAccessPremium)"
|
||||||
id="totpImage"
|
>
|
||||||
|
<span class="totp-countdown">
|
||||||
|
<span class="totp-sec tw-text-muted">15</span>
|
||||||
|
<svg>
|
||||||
|
<g>
|
||||||
|
<circle
|
||||||
|
class="totp-circle-muted inner"
|
||||||
|
r="12.6"
|
||||||
|
cy="16"
|
||||||
|
cx="16"
|
||||||
|
opacity="0.25"
|
||||||
|
[ngStyle]="{ 'stroke-dashoffset.px': 40 }"
|
||||||
|
></circle>
|
||||||
|
<circle
|
||||||
|
class="totp-circle-muted outer"
|
||||||
|
opacity="0.25"
|
||||||
|
r="14"
|
||||||
|
cy="16"
|
||||||
|
cx="16"
|
||||||
|
></circle>
|
||||||
|
</g>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
<span
|
||||||
|
class="totp-code tw-mr-3 tw-ml-2 tw-text-muted"
|
||||||
title="{{ 'verificationCodeTotp' | i18n }}"
|
title="{{ 'verificationCodeTotp' | i18n }}"
|
||||||
class="ml-2"
|
>--- ---</span
|
||||||
/>
|
>
|
||||||
|
<i class="bwi bwi-lg bwi-clone tw-text-muted" aria-hidden="true"></i>
|
||||||
|
</div>
|
||||||
|
<div class="tw-pb-2" *ngIf="!cipher.login.totp || !totpCode">
|
||||||
<app-premium-badge
|
<app-premium-badge
|
||||||
*ngIf="!organization && !cipher.organizationId"
|
*ngIf="!organization && !cipher.organizationId"
|
||||||
class="ml-3"
|
class="ml-3"
|
||||||
@@ -209,8 +236,11 @@
|
|||||||
{{ "upgrade" | i18n }}
|
{{ "upgrade" | i18n }}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="cipher.login.totp && totpCode" class="d-flex align-items-center">
|
<div
|
||||||
<span class="totp-countdown mr-3 ml-2">
|
*ngIf="cipher.login.totp && totpCode && canAccessPremium"
|
||||||
|
class="totp tw-flex tw-flex-row tw-items-center"
|
||||||
|
>
|
||||||
|
<span class="totp-countdown">
|
||||||
<span class="totp-sec">{{ totpSec }}</span>
|
<span class="totp-sec">{{ totpSec }}</span>
|
||||||
<svg>
|
<svg>
|
||||||
<g>
|
<g>
|
||||||
@@ -225,16 +255,18 @@
|
|||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
</span>
|
</span>
|
||||||
<span class="totp-code mr-2" title="{{ 'verificationCodeTotp' | i18n }}">{{
|
<span
|
||||||
totpCodeFormatted
|
class="totp-code tw-mr-2 tw-ml-2 tw-mt-1"
|
||||||
}}</span>
|
title="{{ 'verificationCodeTotp' | i18n }}"
|
||||||
|
>{{ totpCodeFormatted }}</span
|
||||||
|
>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-link"
|
class="tw-items-center tw-border-none tw-bg-transparent tw-text-primary-500"
|
||||||
appA11yTitle="{{ 'copyVerificationCode' | i18n }}"
|
appA11yTitle="{{ 'copyVerificationCode' | i18n }}"
|
||||||
(click)="copy(totpCode, 'verificationCodeTotp', 'TOTP')"
|
(click)="copy(totpCode, 'verificationCodeTotp', 'TOTP')"
|
||||||
>
|
>
|
||||||
<i class="bwi bwi-clone" aria-hidden="true"></i>
|
<i class="bwi bwi-lg bwi-clone" aria-hidden="true"></i>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -152,6 +152,17 @@ export class AddEditComponent extends BaseAddEditComponent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
showGetPremium() {
|
||||||
|
if (this.canAccessPremium) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (this.cipher.organizationUseTotp) {
|
||||||
|
this.upgradeOrganization();
|
||||||
|
} else {
|
||||||
|
this.premiumRequired();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
viewHistory() {
|
viewHistory() {
|
||||||
this.viewingPasswordHistory = !this.viewingPasswordHistory;
|
this.viewingPasswordHistory = !this.viewingPasswordHistory;
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 950 B |
@@ -5220,6 +5220,9 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"premiumSubcriptionRequired": {
|
||||||
|
"message": "Premium subscription required"
|
||||||
|
},
|
||||||
"scim": {
|
"scim": {
|
||||||
"message": "SCIM Provisioning",
|
"message": "SCIM Provisioning",
|
||||||
"description": "The text, 'SCIM', is an acronymn and should not be translated."
|
"description": "The text, 'SCIM', is an acronymn and should not be translated."
|
||||||
|
|||||||
@@ -130,6 +130,25 @@
|
|||||||
stroke-width: 2;
|
stroke-width: 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.totp-circle-muted {
|
||||||
|
fill: none;
|
||||||
|
@include themify($themes) {
|
||||||
|
stroke: themed("info");
|
||||||
|
}
|
||||||
|
|
||||||
|
&.inner {
|
||||||
|
stroke-dasharray: 78.6;
|
||||||
|
stroke-dashoffset: 0;
|
||||||
|
stroke-width: 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.outer {
|
||||||
|
stroke-dasharray: 88;
|
||||||
|
stroke-dashoffset: 0;
|
||||||
|
stroke-width: 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
> .align-items-center {
|
> .align-items-center {
|
||||||
|
|||||||
Reference in New Issue
Block a user