1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-09-19 02:51:14 +02:00

[PM-1802] Update 2fa provider icons and description (#9568)

* Update yubikey to yubico

* Update icons and descriptions

* Change order of 2fa providers

* Refactor 2fa providers into separate component

* Update i18n messages for 2fa providers

* Update design

* Fix link

* Remove unused SVGs

* Undo changes to scss

* Add speedbumps to links

* Fix missing i18n string

* Add a11y tags

* Fix incorrect filepath

* Remove unused i18n strings

* Delete accidentally committed file

* Fix premium and enabled checkmark being in new line

* Rename two-factor-icon selector

* Update authenticator names in two-factor-authenticator setup component

* Update text according to figma design

* Update keys to notify crowdin translators of changed content

* Move svg icons to separate file

* Fix incorrect i18n key
This commit is contained in:
Bernd Schoolmann 2024-06-27 19:14:21 +02:00 committed by GitHub
parent 3c8eeb4420
commit c01f6be286
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 728 additions and 102 deletions

View File

@ -1105,18 +1105,18 @@
"authenticatorAppTitle": {
"message": "Authenticator app"
},
"authenticatorAppDesc": {
"message": "Use an authenticator app (such as Authy or Google Authenticator) to generate time-based verification codes.",
"description": "'Authy' and 'Google Authenticator' are product names and should not be translated."
"authenticatorAppDescV2": {
"message": "Enter a code generated by an authenticator app like Bitwarden Authenticator.",
"description": "'Bitwarden Authenticator' is a product name and should not be translated."
},
"yubiKeyTitle": {
"message": "YubiKey OTP Security Key"
"yubiKeyTitleV2": {
"message": "Yubico OTP Security Key"
},
"yubiKeyDesc": {
"message": "Use a YubiKey to access your account. Works with YubiKey 4, 4 Nano, 4C, and NEO devices."
},
"duoDesc": {
"message": "Verify with Duo Security using the Duo Mobile app, SMS, phone call, or U2F security key.",
"duoDescV2": {
"message": "Enter a code generated by Duo Security.",
"description": "'Duo Security' and 'Duo Mobile' are product names and should not be translated."
},
"duoOrganizationDesc": {
@ -1132,8 +1132,8 @@
"emailTitle": {
"message": "Email"
},
"emailDesc": {
"message": "Verification codes will be emailed to you."
"emailDescV2": {
"message": "Enter a code sent to your email."
},
"selfHostedEnvironment": {
"message": "Self-hosted environment"

View File

@ -5,8 +5,8 @@
"authenticatorAppTitle": {
"message": "Authenticator App"
},
"yubiKeyTitle": {
"message": "YubiKey OTP Security Key"
"yubiKeyTitleV2": {
"message": "Yubico OTP Security Key"
},
"emailTitle": {
"message": "Email"

View File

@ -666,18 +666,18 @@
"authenticatorAppTitle": {
"message": "Authenticator app"
},
"authenticatorAppDesc": {
"message": "Use an authenticator app (such as Authy or Google Authenticator) to generate time-based verification codes.",
"description": "'Authy' and 'Google Authenticator' are product names and should not be translated."
"authenticatorAppDescV2": {
"message": "Enter a code generated by an authenticator app like Bitwarden Authenticator.",
"description": "'Bitwarden Authenticator' is a product name and should not be translated."
},
"yubiKeyTitle": {
"message": "YubiKey OTP security key"
"yubiKeyTitleV2": {
"message": "Yubico OTP security key"
},
"yubiKeyDesc": {
"message": "Use a YubiKey to access your account. Works with YubiKey 4, 4 Nano, 4C, and NEO devices."
},
"duoDesc": {
"message": "Verify with Duo Security using the Duo Mobile app, SMS, phone call, or U2F security key.",
"duoDescV2": {
"message": "Enter a code generated by Duo Security.",
"description": "'Duo Security' and 'Duo Mobile' are product names and should not be translated."
},
"duoOrganizationDesc": {
@ -693,8 +693,8 @@
"emailTitle": {
"message": "Email"
},
"emailDesc": {
"message": "Verification codes will be emailed to you."
"emailDescV2": {
"message": "Enter a code sent to your email."
},
"loginUnavailable": {
"message": "Login unavailable"

View File

@ -5,13 +5,6 @@
<span bitTypography="body1">{{ "authenticatorAppTitle" | i18n }}</span>
</span>
<ng-container bitDialogContent>
<ng-container *ngIf="!enabled">
<img class="float-right mfaType0" alt="Authenticator app logo" />
<p bitTypography="body1">{{ "twoStepAuthenticatorDesc" | i18n }}</p>
<p bitTypography="body1" class="tw-font-bold">
1. {{ "twoStepAuthenticatorDownloadApp" | i18n }}
</p>
</ng-container>
<ng-container *ngIf="enabled">
<bit-callout type="success" title="{{ 'enabled' | i18n }}" icon="bwi-check-circle">
<p bitTypography="body1">{{ "twoStepLoginProviderEnabled" | i18n }}</p>
@ -20,42 +13,64 @@
<img class="float-right mfaType0" alt="Authenticator app logo" />
<p bitTypography="body1">{{ "twoStepAuthenticatorNeedApp" | i18n }}</p>
</ng-container>
<ul class="bwi-ul">
<li>
<i class="bwi bwi-li bwi-apple"></i>{{ "iosDevices" | i18n }}:
<ng-container *ngIf="!enabled">
<p>
{{ "twoStepAuthenticatorInstructionPrefix" | i18n }}
<a
bitLink
href="https://itunes.apple.com/us/app/authy/id494168017?mt=8"
target="_blank"
rel="noreferrer"
>Authy</a
(click)="launchExternalUrl('https://getaegis.app')"
>Aegis</a
>
</li>
<li>
<i class="bwi bwi-li bwi-android"></i>{{ "androidDevices" | i18n }}:
{{ "twoStepAuthenticatorInstructionInfix1" | i18n }}
<a
bitLink
href="https://play.google.com/store/apps/details?id=com.authy.authy"
target="_blank"
rel="noreferrer"
>Authy</a
(click)="launchExternalUrl('https://2fas.com')"
>2FAS</a
>
</li>
<li>
<i class="bwi bwi-li bwi-windows"></i>{{ "windowsDevices" | i18n }}:
{{ "twoStepAuthenticatorInstructionInfix2" | i18n }}
<a
bitLink
href="https://www.microsoft.com/p/authenticator/9wzdncrfj3rj"
target="_blank"
rel="noreferrer"
>Microsoft Authenticator</a
(click)="launchBitwardenUrl('https://bitwarden.com/products/authenticator/')"
>Bitwarden Authenticator</a
>
</li>
</ul>
<p bitTypography="body1">{{ "twoStepAuthenticatorAppsRecommended" | i18n }}</p>
<p *ngIf="!enabled" bitTypography="body1" class="tw-font-bold">
2. {{ "twoStepAuthenticatorScanCode" | i18n }}
</p>
{{ "twoStepAuthenticatorInstructionSuffix" | i18n }}
</p>
<p class="text-center">
<a
href="https://apps.apple.com/ca/app/bitwarden-authenticator/id6497335175"
target="_blank"
>
<img
src="../../../images/download_apple_appstore.svg"
alt="Download on App Store"
max-width="120"
height="40"
/>
</a>
<!--Margin to ensure compliance with google play badge usage guidelines (https://partnermarketinghub.withgoogle.com/brands/google-play/visual-identity/badge-guidelines/#:~:text=The%20clear%20space%20surrounding%20the%20badge%20must%20be%20equal%20to%20one%2Dquarter%20of%20the%20height%20of%20the%20badge.)-->
<a
href="https://play.google.com/store/apps/details?id=com.bitwarden.authenticator"
target="_blank"
>
<img
src="../../../images/download_google_playstore.svg"
alt="Get it on Google Play"
max-width="120"
height="40"
style="margin-left: 10px"
/>
</a>
</p>
{{ "twoStepAuthenticatorScanCodeV2" | i18n }}
</ng-container>
<hr *ngIf="enabled" />
<p class="text-center" [ngClass]="{ 'mb-0': enabled }">
<canvas id="qr"></canvas><br />
@ -63,7 +78,7 @@
</p>
<ng-container *ngIf="!enabled">
<bit-form-field>
<bit-label>3. {{ "twoStepAuthenticatorEnterCode" | i18n }}</bit-label>
<bit-label>{{ "twoStepAuthenticatorEnterCodeV2" | i18n }}</bit-label>
<input bitInput type="text" formControlName="token" appInputVerbatim />
</bit-form-field>
</ng-container>

View File

@ -148,4 +148,29 @@ export class TwoFactorAuthenticatorComponent
) {
return dialogService.open<boolean>(TwoFactorAuthenticatorComponent, config);
}
async launchExternalUrl(url: string) {
const hostname = new URL(url).hostname;
const confirmed = await this.dialogService.openSimpleDialog({
title: this.i18nService.t("continueToExternalUrlTitle", hostname),
content: this.i18nService.t("continueToExternalUrlDesc"),
type: "info",
acceptButtonText: { key: "continue" },
});
if (confirmed) {
this.platformUtilsService.launchUri(url);
}
}
async launchBitwardenUrl(url: string) {
const confirmed = await this.dialogService.openSimpleDialog({
title: this.i18nService.t("twoStepContinueToBitwardenUrlTitle"),
content: this.i18nService.t("twoStepContinueToBitwardenUrlDesc"),
type: "info",
acceptButtonText: { key: "continue" },
});
if (confirmed) {
this.platformUtilsService.launchUri(url);
}
}
}

View File

@ -48,11 +48,16 @@
<ul class="list-group list-group-2fa">
<li *ngFor="let p of providers" class="list-group-item d-flex align-items-center">
<div class="logo-2fa d-flex justify-content-center">
<img [class]="'mfaType' + p.type" [alt]="p.name + ' logo'" />
<auth-two-factor-icon [provider]="p.type" [name]="p.name" />
</div>
<div class="mx-4">
<h3 class="mb-0">
{{ p.name }}
<div
class="font-weight-semibold tw-text-base"
[style]="p.enabled || p.premium ? 'display:inline-block' : ''"
>
{{ p.name }}
</div>
<ng-container *ngIf="p.enabled">
<i
class="bwi bwi-check text-success bwi-fw"

View File

@ -39,7 +39,7 @@
<li>{{ "twoFactorYubikeySupportMobile" | i18n }}</li>
</ul>
</app-callout>
<img class="float-right mfaType3" alt="YubiKey OTP security key logo" />
<img class="float-right mfaType3" alt="Yubico OTP security key logo" />
<p>{{ "twoFactorYubikeyAdd" | i18n }}:</p>
<ol>
<li>{{ "twoFactorYubikeyPlugIn" | i18n }}</li>

View File

@ -5,8 +5,8 @@
<ng-container bitDialogContent>
<div *ngFor="let p of providers" class="tw-m-2">
<div class="tw-flex tw-items-center tw-justify-center tw-gap-4">
<div class="tw-flex tw-items-center tw-justify-center tw-min-w-[100px]">
<img [class]="'mfaType' + p.type" [alt]="p.name + ' logo'" />
<div class="tw-flex tw-items-center tw-justify-center tw-min-w-[120px]">
<auth-two-factor-icon [provider]="p.type" />
</div>
<div class="tw-flex-1">
<h3 bitTypography="h3">{{ p.name }}</h3>
@ -22,8 +22,8 @@
</div>
<div class="tw-m-2" (click)="recover()">
<div class="tw-flex tw-items-center tw-justify-center tw-gap-4">
<div class="tw-flex tw-items-center tw-justify-center tw-min-w-[100px]">
<img class="recovery-code-img" alt="rc logo" />
<div class="tw-flex tw-items-center tw-justify-center tw-min-w-[120px]">
<auth-two-factor-icon provider="rc" />
</div>
<div class="tw-flex-1">
<h3 bitTypography="h3">{{ "recoveryCodeTitle" | i18n }}</h3>

View File

@ -0,0 +1,46 @@
<svg id="livetype" xmlns="http://www.w3.org/2000/svg" width="119.66407" height="40" viewBox="0 0 119.66407 40">
<title>Download_on_the_App_Store_Badge_US-UK_RGB_blk_4SVG_092917</title>
<g>
<g>
<g>
<path d="M110.13477,0H9.53468c-.3667,0-.729,0-1.09473.002-.30615.002-.60986.00781-.91895.0127A13.21476,13.21476,0,0,0,5.5171.19141a6.66509,6.66509,0,0,0-1.90088.627A6.43779,6.43779,0,0,0,1.99757,1.99707,6.25844,6.25844,0,0,0,.81935,3.61816a6.60119,6.60119,0,0,0-.625,1.90332,12.993,12.993,0,0,0-.1792,2.002C.00587,7.83008.00489,8.1377,0,8.44434V31.5586c.00489.3105.00587.6113.01515.9219a12.99232,12.99232,0,0,0,.1792,2.0019,6.58756,6.58756,0,0,0,.625,1.9043A6.20778,6.20778,0,0,0,1.99757,38.001a6.27445,6.27445,0,0,0,1.61865,1.1787,6.70082,6.70082,0,0,0,1.90088.6308,13.45514,13.45514,0,0,0,2.0039.1768c.30909.0068.6128.0107.91895.0107C8.80567,40,9.168,40,9.53468,40H110.13477c.3594,0,.7246,0,1.084-.002.3047,0,.6172-.0039.9219-.0107a13.279,13.279,0,0,0,2-.1768,6.80432,6.80432,0,0,0,1.9082-.6308,6.27742,6.27742,0,0,0,1.6172-1.1787,6.39482,6.39482,0,0,0,1.1816-1.6143,6.60413,6.60413,0,0,0,.6191-1.9043,13.50643,13.50643,0,0,0,.1856-2.0019c.0039-.3106.0039-.6114.0039-.9219.0078-.3633.0078-.7246.0078-1.0938V9.53613c0-.36621,0-.72949-.0078-1.09179,0-.30664,0-.61426-.0039-.9209a13.5071,13.5071,0,0,0-.1856-2.002,6.6177,6.6177,0,0,0-.6191-1.90332,6.46619,6.46619,0,0,0-2.7988-2.7998,6.76754,6.76754,0,0,0-1.9082-.627,13.04394,13.04394,0,0,0-2-.17676c-.3047-.00488-.6172-.01074-.9219-.01269-.3594-.002-.7246-.002-1.084-.002Z" style="fill: #a6a6a6"/>
<path d="M8.44483,39.125c-.30468,0-.602-.0039-.90429-.0107a12.68714,12.68714,0,0,1-1.86914-.1631,5.88381,5.88381,0,0,1-1.65674-.5479,5.40573,5.40573,0,0,1-1.397-1.0166,5.32082,5.32082,0,0,1-1.02051-1.3965,5.72186,5.72186,0,0,1-.543-1.6572,12.41351,12.41351,0,0,1-.1665-1.875c-.00634-.2109-.01464-.9131-.01464-.9131V8.44434S.88185,7.75293.8877,7.5498a12.37039,12.37039,0,0,1,.16553-1.87207,5.7555,5.7555,0,0,1,.54346-1.6621A5.37349,5.37349,0,0,1,2.61183,2.61768,5.56543,5.56543,0,0,1,4.01417,1.59521a5.82309,5.82309,0,0,1,1.65332-.54394A12.58589,12.58589,0,0,1,7.543.88721L8.44532.875H111.21387l.9131.0127a12.38493,12.38493,0,0,1,1.8584.16259,5.93833,5.93833,0,0,1,1.6709.54785,5.59374,5.59374,0,0,1,2.415,2.41993,5.76267,5.76267,0,0,1,.5352,1.64892,12.995,12.995,0,0,1,.1738,1.88721c.0029.2832.0029.5874.0029.89014.0079.375.0079.73193.0079,1.09179V30.4648c0,.3633,0,.7178-.0079,1.0752,0,.3252,0,.6231-.0039.9297a12.73126,12.73126,0,0,1-.1709,1.8535,5.739,5.739,0,0,1-.54,1.67,5.48029,5.48029,0,0,1-1.0156,1.3857,5.4129,5.4129,0,0,1-1.3994,1.0225,5.86168,5.86168,0,0,1-1.668.5498,12.54218,12.54218,0,0,1-1.8692.1631c-.2929.0068-.5996.0107-.8974.0107l-1.084.002Z"/>
</g>
<g id="_Group_" data-name="&lt;Group&gt;">
<g id="_Group_2" data-name="&lt;Group&gt;">
<g id="_Group_3" data-name="&lt;Group&gt;">
<path id="_Path_" data-name="&lt;Path&gt;" d="M24.76888,20.30068a4.94881,4.94881,0,0,1,2.35656-4.15206,5.06566,5.06566,0,0,0-3.99116-2.15768c-1.67924-.17626-3.30719,1.00483-4.1629,1.00483-.87227,0-2.18977-.98733-3.6085-.95814a5.31529,5.31529,0,0,0-4.47292,2.72787c-1.934,3.34842-.49141,8.26947,1.3612,10.97608.9269,1.32535,2.01018,2.8058,3.42763,2.7533,1.38706-.05753,1.9051-.88448,3.5794-.88448,1.65876,0,2.14479.88448,3.591.8511,1.48838-.02416,2.42613-1.33124,3.32051-2.66914a10.962,10.962,0,0,0,1.51842-3.09251A4.78205,4.78205,0,0,1,24.76888,20.30068Z" style="fill: #fff"/>
<path id="_Path_2" data-name="&lt;Path&gt;" d="M22.03725,12.21089a4.87248,4.87248,0,0,0,1.11452-3.49062,4.95746,4.95746,0,0,0-3.20758,1.65961,4.63634,4.63634,0,0,0-1.14371,3.36139A4.09905,4.09905,0,0,0,22.03725,12.21089Z" style="fill: #fff"/>
</g>
</g>
<g>
<path d="M42.30227,27.13965h-4.7334l-1.13672,3.35645H34.42727l4.4834-12.418h2.083l4.4834,12.418H43.438ZM38.0591,25.59082h3.752l-1.84961-5.44727h-.05176Z" style="fill: #fff"/>
<path d="M55.15969,25.96973c0,2.81348-1.50586,4.62109-3.77832,4.62109a3.0693,3.0693,0,0,1-2.84863-1.584h-.043v4.48438h-1.8584V21.44238H48.4302v1.50586h.03418a3.21162,3.21162,0,0,1,2.88281-1.60059C53.645,21.34766,55.15969,23.16406,55.15969,25.96973Zm-1.91016,0c0-1.833-.94727-3.03809-2.39258-3.03809-1.41992,0-2.375,1.23047-2.375,3.03809,0,1.82422.95508,3.0459,2.375,3.0459C52.30227,29.01563,53.24953,27.81934,53.24953,25.96973Z" style="fill: #fff"/>
<path d="M65.12453,25.96973c0,2.81348-1.50586,4.62109-3.77832,4.62109a3.0693,3.0693,0,0,1-2.84863-1.584h-.043v4.48438h-1.8584V21.44238H58.395v1.50586h.03418A3.21162,3.21162,0,0,1,61.312,21.34766C63.60988,21.34766,65.12453,23.16406,65.12453,25.96973Zm-1.91016,0c0-1.833-.94727-3.03809-2.39258-3.03809-1.41992,0-2.375,1.23047-2.375,3.03809,0,1.82422.95508,3.0459,2.375,3.0459C62.26711,29.01563,63.21438,27.81934,63.21438,25.96973Z" style="fill: #fff"/>
<path d="M71.71047,27.03613c.1377,1.23145,1.334,2.04,2.96875,2.04,1.56641,0,2.69336-.80859,2.69336-1.91895,0-.96387-.67969-1.541-2.28906-1.93652l-1.60937-.3877c-2.28027-.55078-3.33887-1.61719-3.33887-3.34766,0-2.14258,1.86719-3.61426,4.51855-3.61426,2.624,0,4.42285,1.47168,4.4834,3.61426h-1.876c-.1123-1.23926-1.13672-1.9873-2.63379-1.9873s-2.52148.75684-2.52148,1.8584c0,.87793.6543,1.39453,2.25488,1.79l1.36816.33594c2.54785.60254,3.60645,1.626,3.60645,3.44238,0,2.32324-1.85059,3.77832-4.79395,3.77832-2.75391,0-4.61328-1.4209-4.7334-3.667Z" style="fill: #fff"/>
<path d="M83.34621,19.2998v2.14258h1.72168v1.47168H83.34621v4.99121c0,.77539.34473,1.13672,1.10156,1.13672a5.80752,5.80752,0,0,0,.61133-.043v1.46289a5.10351,5.10351,0,0,1-1.03223.08594c-1.833,0-2.54785-.68848-2.54785-2.44434V22.91406H80.16262V21.44238H81.479V19.2998Z" style="fill: #fff"/>
<path d="M86.065,25.96973c0-2.84863,1.67773-4.63867,4.29395-4.63867,2.625,0,4.29492,1.79,4.29492,4.63867,0,2.85645-1.66113,4.63867-4.29492,4.63867C87.72609,30.6084,86.065,28.82617,86.065,25.96973Zm6.69531,0c0-1.9541-.89551-3.10742-2.40137-3.10742s-2.40039,1.16211-2.40039,3.10742c0,1.96191.89453,3.10645,2.40039,3.10645S92.76027,27.93164,92.76027,25.96973Z" style="fill: #fff"/>
<path d="M96.18606,21.44238h1.77246v1.541h.043a2.1594,2.1594,0,0,1,2.17773-1.63574,2.86616,2.86616,0,0,1,.63672.06934v1.73828a2.59794,2.59794,0,0,0-.835-.1123,1.87264,1.87264,0,0,0-1.93652,2.083v5.37012h-1.8584Z" style="fill: #fff"/>
<path d="M109.3843,27.83691c-.25,1.64355-1.85059,2.77148-3.89844,2.77148-2.63379,0-4.26855-1.76465-4.26855-4.5957,0-2.83984,1.64355-4.68164,4.19043-4.68164,2.50488,0,4.08008,1.7207,4.08008,4.46582v.63672h-6.39453v.1123a2.358,2.358,0,0,0,2.43555,2.56445,2.04834,2.04834,0,0,0,2.09082-1.27344Zm-6.28223-2.70215h4.52637a2.1773,2.1773,0,0,0-2.2207-2.29785A2.292,2.292,0,0,0,103.10207,25.13477Z" style="fill: #fff"/>
</g>
</g>
</g>
<g id="_Group_4" data-name="&lt;Group&gt;">
<g>
<path d="M37.82619,8.731a2.63964,2.63964,0,0,1,2.80762,2.96484c0,1.90625-1.03027,3.002-2.80762,3.002H35.67092V8.731Zm-1.22852,5.123h1.125a1.87588,1.87588,0,0,0,1.96777-2.146,1.881,1.881,0,0,0-1.96777-2.13379h-1.125Z" style="fill: #fff"/>
<path d="M41.68068,12.44434a2.13323,2.13323,0,1,1,4.24707,0,2.13358,2.13358,0,1,1-4.24707,0Zm3.333,0c0-.97607-.43848-1.54687-1.208-1.54687-.77246,0-1.207.5708-1.207,1.54688,0,.98389.43457,1.55029,1.207,1.55029C44.57522,13.99463,45.01369,13.42432,45.01369,12.44434Z" style="fill: #fff"/>
<path d="M51.57326,14.69775h-.92187l-.93066-3.31641h-.07031l-.92676,3.31641h-.91309l-1.24121-4.50293h.90137l.80664,3.436h.06641l.92578-3.436h.85254l.92578,3.436h.07031l.80273-3.436h.88867Z" style="fill: #fff"/>
<path d="M53.85354,10.19482H54.709v.71533h.06641a1.348,1.348,0,0,1,1.34375-.80225,1.46456,1.46456,0,0,1,1.55859,1.6748v2.915h-.88867V12.00586c0-.72363-.31445-1.0835-.97168-1.0835a1.03294,1.03294,0,0,0-1.0752,1.14111v2.63428h-.88867Z" style="fill: #fff"/>
<path d="M59.09377,8.437h.88867v6.26074h-.88867Z" style="fill: #fff"/>
<path d="M61.21779,12.44434a2.13346,2.13346,0,1,1,4.24756,0,2.1338,2.1338,0,1,1-4.24756,0Zm3.333,0c0-.97607-.43848-1.54687-1.208-1.54687-.77246,0-1.207.5708-1.207,1.54688,0,.98389.43457,1.55029,1.207,1.55029C64.11232,13.99463,64.5508,13.42432,64.5508,12.44434Z" style="fill: #fff"/>
<path d="M66.4009,13.42432c0-.81055.60352-1.27783,1.6748-1.34424l1.21973-.07031v-.38867c0-.47559-.31445-.74414-.92187-.74414-.49609,0-.83984.18213-.93848.50049h-.86035c.09082-.77344.81836-1.26953,1.83984-1.26953,1.12891,0,1.76563.562,1.76563,1.51318v3.07666h-.85547v-.63281h-.07031a1.515,1.515,0,0,1-1.35254.707A1.36026,1.36026,0,0,1,66.4009,13.42432Zm2.89453-.38477v-.37646l-1.09961.07031c-.62012.0415-.90137.25244-.90137.64941,0,.40527.35156.64111.835.64111A1.0615,1.0615,0,0,0,69.29543,13.03955Z" style="fill: #fff"/>
<path d="M71.34816,12.44434c0-1.42285.73145-2.32422,1.86914-2.32422a1.484,1.484,0,0,1,1.38086.79h.06641V8.437h.88867v6.26074h-.85156v-.71143h-.07031a1.56284,1.56284,0,0,1-1.41406.78564C72.0718,14.772,71.34816,13.87061,71.34816,12.44434Zm.918,0c0,.95508.4502,1.52979,1.20313,1.52979.749,0,1.21191-.583,1.21191-1.52588,0-.93848-.46777-1.52979-1.21191-1.52979C72.72121,10.91846,72.26613,11.49707,72.26613,12.44434Z" style="fill: #fff"/>
<path d="M79.23,12.44434a2.13323,2.13323,0,1,1,4.24707,0,2.13358,2.13358,0,1,1-4.24707,0Zm3.333,0c0-.97607-.43848-1.54687-1.208-1.54687-.77246,0-1.207.5708-1.207,1.54688,0,.98389.43457,1.55029,1.207,1.55029C82.12453,13.99463,82.563,13.42432,82.563,12.44434Z" style="fill: #fff"/>
<path d="M84.66945,10.19482h.85547v.71533h.06641a1.348,1.348,0,0,1,1.34375-.80225,1.46456,1.46456,0,0,1,1.55859,1.6748v2.915H87.605V12.00586c0-.72363-.31445-1.0835-.97168-1.0835a1.03294,1.03294,0,0,0-1.0752,1.14111v2.63428h-.88867Z" style="fill: #fff"/>
<path d="M93.51516,9.07373v1.1416h.97559v.74854h-.97559V13.2793c0,.47168.19434.67822.63672.67822a2.96657,2.96657,0,0,0,.33887-.02051v.74023a2.9155,2.9155,0,0,1-.4834.04541c-.98828,0-1.38184-.34766-1.38184-1.21582v-2.543h-.71484v-.74854h.71484V9.07373Z" style="fill: #fff"/>
<path d="M95.70461,8.437h.88086v2.48145h.07031a1.3856,1.3856,0,0,1,1.373-.80664,1.48339,1.48339,0,0,1,1.55078,1.67871v2.90723H98.69v-2.688c0-.71924-.335-1.0835-.96289-1.0835a1.05194,1.05194,0,0,0-1.13379,1.1416v2.62988h-.88867Z" style="fill: #fff"/>
<path d="M104.76125,13.48193a1.828,1.828,0,0,1-1.95117,1.30273A2.04531,2.04531,0,0,1,100.73,12.46045a2.07685,2.07685,0,0,1,2.07617-2.35254c1.25293,0,2.00879.856,2.00879,2.27V12.688h-3.17969v.0498a1.1902,1.1902,0,0,0,1.19922,1.29,1.07934,1.07934,0,0,0,1.07129-.5459Zm-3.126-1.45117h2.27441a1.08647,1.08647,0,0,0-1.1084-1.1665A1.15162,1.15162,0,0,0,101.63527,12.03076Z" style="fill: #fff"/>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -0,0 +1,275 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
version="1.1"
id="svg1"
width="180"
height="53.334"
viewBox="0 0 180 53.334"
sodipodi:docname="download_google_playstore.svg"
inkscape:version="1.3.2 (091e20e, 2023-11-25)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<defs
id="defs1">
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath1">
<path
d="M 0,60 H 155 V 0 H 0 Z"
id="path1" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath3">
<path
d="M 0,60 H 155 V 0 H 0 Z"
transform="matrix(1.3333333,0,0,-1.3333333,0,80)"
id="path3" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath5">
<path
d="M 0,60 H 155 V 0 H 0 Z"
transform="translate(-140.0001,-10.000101)"
id="path5" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath7">
<path
d="M 0,60 H 155 V 0 H 0 Z"
transform="translate(-140.0001,-49.999901)"
id="path7" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath9">
<path
d="M 0,60 H 155 V 0 H 0 Z"
transform="translate(-57.418501,-39.756801)"
id="path9" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath11">
<path
d="M 0,60 H 155 V 0 H 0 Z"
transform="translate(-62.027801,-42.262701)"
id="path11" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath13">
<path
d="M 0,60 H 155 V 0 H 0 Z"
transform="translate(-65.278802,-37.000001)"
id="path13" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath15">
<path
d="M 0,60 H 155 V 0 H 0 Z"
id="path15" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath17">
<path
d="M 0,60 H 155 V 0 H 0 Z"
transform="translate(-74.128402,-37.000001)"
id="path17" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath19">
<path
d="M 0,60 H 155 V 0 H 0 Z"
transform="translate(-79.779302,-38.277801)"
id="path19" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath21">
<path
d="M 0,60 H 155 V 0 H 0 Z"
transform="translate(-79.779302,-38.277801)"
id="path21" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath23">
<path
d="M 0,60 H 155 V 0 H 0 Z"
transform="translate(-85.575205,-37.000001)"
id="path23" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath25">
<path
d="M 0,60 H 155 V 0 H 0 Z"
id="path25" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath27">
<path
d="M 0,60 H 155 V 0 H 0 Z"
transform="translate(-30.717301,-30.575901)"
id="path27" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath29">
<path
d="M 0,60 H 155 V 0 H 0 Z"
transform="translate(-41.488201,-32.500101)"
id="path29" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath31">
<path
d="M 0,60 H 155 V 0 H 0 Z"
transform="translate(-20.0701,-40.722901)"
id="path31" />
</clipPath>
<clipPath
clipPathUnits="userSpaceOnUse"
id="clipPath33">
<path
d="M 0,60 H 155 V 0 H 0 Z"
transform="translate(-30.795901,-29.999101)"
id="path33" />
</clipPath>
</defs>
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:zoom="7.8270972"
inkscape:cx="72.249006"
inkscape:cy="58.961833"
inkscape:window-width="2336"
inkscape:window-height="1626"
inkscape:window-x="927"
inkscape:window-y="286"
inkscape:window-maximized="0"
inkscape:current-layer="layer-MC0">
<inkscape:page
x="0"
y="0"
inkscape:label="1"
id="page1"
width="180"
height="53.334"
margin="0"
bleed="0" />
</sodipodi:namedview>
<g
id="layer-MC0"
inkscape:groupmode="layer"
inkscape:label="artwork">
<path
id="path4"
d="m 0,0 h -125 c -2.75,0 -5,2.25 -5,5 v 30 c 0,2.75 2.25,5 5,5 H 0 c 2.75,0 5,-2.25 5,-5 V 5 C 5,2.25 2.75,0 0,0"
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
transform="matrix(1.3333333,0,0,-1.3333333,173.33333,53.333332)"
clip-path="url(#clipPath5)" />
<path
id="path6"
d="m 0,0 h -125 c -2.75,0 -5,-2.25 -5,-5 v -30 c 0,-2.75 2.25,-5 5,-5 H 0 c 2.75,0 5,2.25 5,5 V -5 C 5,-2.25 2.75,0 0,0 m 0,-0.8 c 2.316,0 4.2,-1.884 4.2,-4.2 v -30 c 0,-2.316 -1.884,-4.2 -4.2,-4.2 h -125 c -2.316,0 -4.2,1.884 -4.2,4.2 v 30 c 0,2.316 1.884,4.2 4.2,4.2 z"
style="fill:#a6a6a6;fill-opacity:1;fill-rule:nonzero;stroke:none"
transform="matrix(1.3333333,0,0,-1.3333333,173.33333,2.6637e-4)"
clip-path="url(#clipPath7)" />
<path
id="path8"
d="m 0,0 c 0,-0.838 -0.248,-1.505 -0.745,-2.003 -0.565,-0.592 -1.3,-0.888 -2.204,-0.888 -0.867,0 -1.603,0.3 -2.208,0.901 -0.607,0.6 -0.909,1.345 -0.909,2.233 0,0.889 0.302,1.633 0.909,2.234 0.605,0.6 1.341,0.901 2.208,0.901 0.429,0 0.841,-0.084 1.231,-0.252 0.391,-0.168 0.704,-0.391 0.939,-0.67 L -1.307,1.928 C -1.704,2.402 -2.251,2.64 -2.949,2.64 -3.581,2.64 -4.127,2.418 -4.588,1.974 -5.049,1.529 -5.279,0.953 -5.279,0.243 c 0,-0.709 0.23,-1.286 0.691,-1.73 0.461,-0.445 1.007,-0.666 1.639,-0.666 0.67,0 1.228,0.223 1.676,0.67 0.29,0.291 0.457,0.695 0.502,1.215 h -2.178 v 0.721 h 2.907 C -0.014,0.296 0,0.145 0,0"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
transform="matrix(1.3333333,0,0,-1.3333333,63.224531,13.657732)"
clip-path="url(#clipPath9)" />
<path
id="path10"
d="m 0,0 h -2.732 v -1.902 h 2.464 V -2.623 H -2.732 V -4.525 H 0 v -0.738 h -3.503 v 6 H 0 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
transform="matrix(1.3333333,0,0,-1.3333333,69.370264,10.316532)"
clip-path="url(#clipPath11)" />
<path
id="path12"
d="M 0,0 H -0.771 V 5.263 H -2.447 V 6 H 1.676 V 5.263 H 0 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
transform="matrix(1.3333333,0,0,-1.3333333,73.704931,17.333466)"
clip-path="url(#clipPath13)" />
<path
id="path14"
d="m 69.938,43 h 0.771 v -6 h -0.771 z"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
transform="matrix(1.3333333,0,0,-1.3333333,-13.333469,66.666799)"
clip-path="url(#clipPath15)" />
<path
id="path16"
d="M 0,0 H -0.771 V 5.263 H -2.447 V 6 H 1.676 V 5.263 H 0 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
transform="matrix(1.3333333,0,0,-1.3333333,85.504398,17.333466)"
clip-path="url(#clipPath17)" />
<path
id="path18"
d="M 0,0 C 0.444,-0.45 0.987,-0.674 1.63,-0.674 2.273,-0.674 2.816,-0.45 3.26,0 3.704,0.45 3.927,1.024 3.927,1.722 3.927,2.42 3.704,2.995 3.26,3.444 2.816,3.894 2.273,4.119 1.63,4.119 0.987,4.119 0.444,3.894 0,3.444 -0.443,2.995 -0.666,2.42 -0.666,1.722 -0.666,1.024 -0.443,0.45 0,0 m 3.83,-0.502 c -0.59,-0.607 -1.323,-0.91 -2.2,-0.91 -0.877,0 -1.61,0.303 -2.199,0.91 -0.59,0.606 -0.884,1.347 -0.884,2.224 0,0.877 0.294,1.619 0.884,2.225 0.589,0.606 1.322,0.91 2.199,0.91 0.872,0 1.603,-0.305 2.196,-0.914 C 4.418,3.334 4.714,2.594 4.714,1.722 4.714,0.845 4.419,0.104 3.83,-0.502"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
transform="matrix(1.3333333,0,0,-1.3333333,93.038931,15.629732)"
clip-path="url(#clipPath19)" />
<path
id="path20"
d="M 0,0 C 0.444,-0.45 0.987,-0.674 1.63,-0.674 2.273,-0.674 2.816,-0.45 3.26,0 3.704,0.45 3.927,1.024 3.927,1.722 3.927,2.42 3.704,2.995 3.26,3.444 2.816,3.894 2.273,4.119 1.63,4.119 0.987,4.119 0.444,3.894 0,3.444 -0.443,2.995 -0.666,2.42 -0.666,1.722 -0.666,1.024 -0.443,0.45 0,0 Z m 3.83,-0.502 c -0.59,-0.607 -1.323,-0.91 -2.2,-0.91 -0.877,0 -1.61,0.303 -2.199,0.91 -0.59,0.606 -0.884,1.347 -0.884,2.224 0,0.877 0.294,1.619 0.884,2.225 0.589,0.606 1.322,0.91 2.199,0.91 0.872,0 1.603,-0.305 2.196,-0.914 C 4.418,3.334 4.714,2.594 4.714,1.722 4.714,0.845 4.419,0.104 3.83,-0.502 Z"
style="fill:none;stroke:#ffffff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
transform="matrix(1.3333333,0,0,-1.3333333,93.038931,15.629732)"
clip-path="url(#clipPath21)" />
<path
id="path22"
d="M 0,0 V 6 H 0.938 L 3.854,1.333 H 3.888 L 3.854,2.489 V 6 H 4.626 V 0 H 3.821 L 0.77,4.894 H 0.737 L 0.77,3.737 V 0 Z"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:#ffffff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:10;stroke-dasharray:none;stroke-opacity:1"
transform="matrix(1.3333333,0,0,-1.3333333,100.7668,17.333466)"
clip-path="url(#clipPath23)" />
<path
id="path24"
d="m 116.936,20 h 1.866 v 12.501 h -1.866 z m 16.807,7.998 -2.139,-5.42 h -0.064 l -2.22,5.42 h -2.01 l 3.329,-7.575 -1.897,-4.214 h 1.945 l 5.131,11.789 z M 123.161,21.42 c -0.612,0 -1.464,0.305 -1.464,1.062 0,0.964 1.061,1.334 1.978,1.334 0.82,0 1.207,-0.177 1.705,-0.418 -0.145,-1.158 -1.142,-1.978 -2.219,-1.978 m 0.225,6.851 c -1.351,0 -2.751,-0.595 -3.329,-1.914 l 1.656,-0.691 c 0.354,0.691 1.013,0.917 1.705,0.917 0.965,0 1.946,-0.579 1.962,-1.609 v -0.128 c -0.338,0.193 -1.061,0.482 -1.946,0.482 -1.785,0 -3.603,-0.981 -3.603,-2.814 0,-1.673 1.464,-2.751 3.104,-2.751 1.255,0 1.947,0.563 2.381,1.223 h 0.064 v -0.965 h 1.801 v 4.793 c 0,2.219 -1.656,3.457 -3.795,3.457 M 111.854,26.476 H 109.2 v 4.285 h 2.654 c 1.395,0 2.187,-1.155 2.187,-2.142 0,-0.969 -0.792,-2.143 -2.187,-2.143 m -0.048,6.025 h -4.471 V 20 h 1.865 v 4.736 h 2.606 c 2.068,0 4.101,1.498 4.101,3.883 0,2.385 -2.033,3.882 -4.101,3.882 M 87.425,21.418 c -1.289,0 -2.368,1.079 -2.368,2.561 0,1.498 1.079,2.594 2.368,2.594 1.273,0 2.271,-1.096 2.271,-2.594 0,-1.482 -0.998,-2.561 -2.271,-2.561 m 2.143,5.88 h -0.065 c -0.419,0.499 -1.224,0.95 -2.239,0.95 -2.127,0 -4.076,-1.868 -4.076,-4.269 0,-2.384 1.949,-4.237 4.076,-4.237 1.015,0 1.82,0.451 2.239,0.967 h 0.065 v -0.613 c 0,-1.627 -0.87,-2.497 -2.272,-2.497 -1.144,0 -1.853,0.822 -2.143,1.515 l -1.627,-0.677 c 0.467,-1.128 1.708,-2.513 3.77,-2.513 2.191,0 4.044,1.289 4.044,4.43 v 7.637 H 89.568 Z M 92.629,20 h 1.869 v 12.502 h -1.869 z m 4.623,4.124 c -0.048,1.643 1.273,2.481 2.223,2.481 0.742,0 1.37,-0.37 1.579,-0.902 z m 5.8,1.418 c -0.354,0.95 -1.434,2.706 -3.641,2.706 -2.191,0 -4.011,-1.723 -4.011,-4.253 0,-2.384 1.804,-4.253 4.22,-4.253 1.95,0 3.078,1.192 3.545,1.885 l -1.45,0.967 c -0.483,-0.709 -1.144,-1.176 -2.095,-1.176 -0.95,0 -1.627,0.435 -2.062,1.288 l 5.687,2.353 z m -45.308,1.401 v -1.804 h 4.317 c -0.129,-1.015 -0.467,-1.756 -0.982,-2.271 -0.629,-0.629 -1.612,-1.322 -3.335,-1.322 -2.659,0 -4.737,2.143 -4.737,4.801 0,2.659 2.078,4.801 4.737,4.801 1.434,0 2.481,-0.564 3.254,-1.289 l 1.273,1.273 c -1.08,1.031 -2.513,1.821 -4.527,1.821 -3.641,0 -6.702,-2.965 -6.702,-6.606 0,-3.641 3.061,-6.605 6.702,-6.605 1.965,0 3.447,0.645 4.607,1.853 1.193,1.192 1.563,2.867 1.563,4.221 0,0.419 -0.032,0.805 -0.097,1.127 z m 11.079,-5.525 c -1.289,0 -2.401,1.063 -2.401,2.577 0,1.531 1.112,2.578 2.401,2.578 1.288,0 2.4,-1.047 2.4,-2.578 0,-1.514 -1.112,-2.577 -2.4,-2.577 m 0,6.83 c -2.353,0 -4.27,-1.788 -4.27,-4.253 0,-2.449 1.917,-4.253 4.27,-4.253 2.352,0 4.269,1.804 4.269,4.253 0,2.465 -1.917,4.253 -4.269,4.253 m 9.313,-6.83 c -1.289,0 -2.401,1.063 -2.401,2.577 0,1.531 1.112,2.578 2.401,2.578 1.289,0 2.4,-1.047 2.4,-2.578 0,-1.514 -1.111,-2.577 -2.4,-2.577 m 0,6.83 c -2.352,0 -4.269,-1.788 -4.269,-4.253 0,-2.449 1.917,-4.253 4.269,-4.253 2.352,0 4.269,1.804 4.269,4.253 0,2.465 -1.917,4.253 -4.269,4.253"
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none"
transform="matrix(1.3333333,0,0,-1.3333333,-13.333469,66.666799)"
clip-path="url(#clipPath25)" />
<path
id="path26"
d="m 0,0 -10.647,-11.3 c 10e-4,-0.002 10e-4,-0.005 0.002,-0.007 0.327,-1.227 1.447,-2.13 2.777,-2.13 0.532,0 1.031,0.144 1.459,0.396 l 0.034,0.02 11.984,6.915 z"
style="fill:#ea4335;fill-opacity:1;fill-rule:nonzero;stroke:none"
transform="matrix(1.3333333,0,0,-1.3333333,27.622931,25.898932)"
clip-path="url(#clipPath27)" />
<path
id="path28"
d="m 0,0 -0.01,0.007 -5.174,2.999 -5.829,-5.187 5.85,-5.848 5.146,2.969 c 0.902,0.488 1.515,1.439 1.515,2.535 C 1.498,-1.435 0.894,-0.489 0,0"
style="fill:#fbbc04;fill-opacity:1;fill-rule:nonzero;stroke:none"
transform="matrix(1.3333333,0,0,-1.3333333,41.984131,23.333332)"
clip-path="url(#clipPath29)" />
<path
id="path30"
d="m 0,0 c -0.064,-0.236 -0.098,-0.484 -0.098,-0.74 v -19.968 c 0,-0.256 0.034,-0.504 0.099,-0.739 l 11.012,11.011 z"
style="fill:#4285f4;fill-opacity:1;fill-rule:nonzero;stroke:none"
transform="matrix(1.3333333,0,0,-1.3333333,13.426664,12.369599)"
clip-path="url(#clipPath31)" />
<path
id="path32"
d="m 0,0 5.51,5.509 -11.97,6.94 c -0.435,0.261 -0.943,0.411 -1.486,0.411 -1.33,0 -2.452,-0.905 -2.779,-2.133 0,-10e-4 -0.001,-0.002 -0.001,-0.003 z"
style="fill:#34a853;fill-opacity:1;fill-rule:nonzero;stroke:none"
transform="matrix(1.3333333,0,0,-1.3333333,27.727731,26.667999)"
clip-path="url(#clipPath33)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -962,18 +962,18 @@
"authenticatorAppTitle": {
"message": "Authenticator app"
},
"authenticatorAppDesc": {
"message": "Use an authenticator app (such as Authy or Google Authenticator) to generate time-based verification codes.",
"description": "'Authy' and 'Google Authenticator' are product names and should not be translated."
"authenticatorAppDescV2": {
"message": "Enter a code generated by an authenticator app like Bitwarden Authenticator.",
"description": "'Bitwarden Authenticator' is a product name and should not be translated."
},
"yubiKeyTitle": {
"message": "YubiKey OTP security key"
"yubiKeyTitleV2": {
"message": "Yubico OTP security key"
},
"yubiKeyDesc": {
"message": "Use a YubiKey to access your account. Works with YubiKey 4 series, 5 series, and NEO devices."
"message": "Use a YubiKey 4, 5 or NEO device."
},
"duoDesc": {
"message": "Verify with Duo Security using the Duo Mobile app, SMS, phone call, or U2F security key.",
"duoDescV2": {
"message": "Enter a code generated by Duo Security.",
"description": "'Duo Security' and 'Duo Mobile' are product names and should not be translated."
},
"duoOrganizationDesc": {
@ -984,13 +984,13 @@
"message": "Use any FIDO U2F compatible security key to access your account."
},
"u2fTitle": {
"message": "FIDO U2F security key"
"message": "FIDO U2F security a key"
},
"webAuthnTitle": {
"message": "FIDO2 WebAuthn"
"message": "Passkey"
},
"webAuthnDesc": {
"message": "Use any WebAuthn compatible security key to access your account."
"message": "Use your device's biometrics or a FIDO2 compatible security key."
},
"webAuthnMigrated": {
"message": "(Migrated from FIDO)"
@ -998,8 +998,8 @@
"emailTitle": {
"message": "Email"
},
"emailDesc": {
"message": "Verification codes will be emailed to you."
"emailDescV2": {
"message": "Enter a code sent to your email."
},
"continue": {
"message": "Continue"
@ -1639,35 +1639,44 @@
"twoStepLoginAuthDesc": {
"message": "Enter your master password to modify two-step login settings."
},
"twoStepAuthenticatorDesc": {
"message": "Follow these steps to set up two-step login with an authenticator app:"
"twoStepAuthenticatorInstructionPrefix": {
"message": "Download an authenticator app such as"
},
"twoStepAuthenticatorDownloadApp": {
"message": "Download a two-step authenticator app"
"twoStepAuthenticatorInstructionInfix1": {
"message": ","
},
"twoStepAuthenticatorNeedApp": {
"message": "Need a two-step authenticator app? Download one of the following"
"twoStepAuthenticatorInstructionInfix2": {
"message": "or"
},
"iosDevices": {
"message": "iOS devices"
"twoStepAuthenticatorInstructionSuffix": {
"message": "."
},
"androidDevices": {
"message": "Android devices"
"continueToExternalUrlTitle": {
"message": "Continue to $URL$?",
"placeholders": {
"url": {
"content": "$1",
"example": "bitwarden.com"
}
}
},
"windowsDevices": {
"message": "Windows devices"
"continueToExternalUrlDesc": {
"message": "You are leaving Bitwarden and launching an external website in a new window."
},
"twoStepAuthenticatorAppsRecommended": {
"message": "These apps are recommended, however, other authenticator apps will also work."
"twoStepContinueToBitwardenUrlTitle": {
"message": "Continue to bitwarden.com?"
},
"twoStepAuthenticatorScanCode": {
"message": "Scan this QR code with your authenticator app"
"twoStepContinueToBitwardenUrlDesc": {
"message": "Bitwarden Authenticator allows you to store authenticator keys and generate TOTP codes for 2-step verification flows. Learn more on the bitwarden.com website."
},
"twoStepAuthenticatorScanCodeV2": {
"message": "Scan the QR code below with your authenticator app or enter the key."
},
"key": {
"message": "Key"
},
"twoStepAuthenticatorEnterCode": {
"message": "Enter the resulting 6 digit verification code from the app"
"twoStepAuthenticatorEnterCodeV2": {
"message": "Verification code"
},
"twoStepAuthenticatorReaddDesc": {
"message": "In case you need to add it to another device, below is the QR code (or key) required by your authenticator app."

View File

@ -32,29 +32,37 @@
.list-group-2fa {
.logo-2fa {
min-width: 100px;
min-width: 120px;
}
}
@each $mfaType in $mfaTypes {
.mfaType#{$mfaType} {
content: url("../images/two-factor/" + $mfaType + ".png");
max-width: 100px;
max-width: 120px;
}
}
.mfaType0 {
@include themify($themes) {
content: url("../images/two-factor/0.png");
max-width: 120px;
max-height: 62px;
}
}
.mfaType1 {
@include themify($themes) {
content: url("../images/two-factor/1" + themed("mfaLogoSuffix"));
max-width: 100px;
max-height: 45px;
max-width: 120px;
max-height: 62px;
}
}
.mfaType7 {
@include themify($themes) {
content: url("../images/two-factor/7" + themed("mfaLogoSuffix"));
max-width: 100px;
max-width: 120px;
}
}

View File

@ -0,0 +1,16 @@
<ng-container>
<!-- TOTP Authenticator -->
<bit-icon [icon]="Icons.TOTPIcon" *ngIf="provider == 0"></bit-icon>
<!-- Email -->
<bit-icon [icon]="Icons.EmailIcon" *ngIf="provider == 1"></bit-icon>
<!-- Webauthn -->
<bit-icon [icon]="Icons.WebAuthnIcon" *ngIf="provider == 7"></bit-icon>
<!-- Recovery Code -->
<bit-icon [icon]="Icons.RecoveryCodeIcon" *ngIf="provider == 'rc'"></bit-icon>
<!-- Other 2FA Types (Duo, Yubico, U2F as PNG) -->
<img
[class]="'mfaType' + provider"
[alt]="name"
*ngIf="provider == 2 || provider == 3 || provider == 4 || provider == 5 || provider == 6"
/>
</ng-container>

View File

@ -0,0 +1,24 @@
import { Component, Input } from "@angular/core";
import { EmailIcon } from "../icons/email.icon";
import { RecoveryCodeIcon } from "../icons/recovery.icon";
import { TOTPIcon } from "../icons/totp.icon";
import { WebAuthnIcon } from "../icons/webauthn.icon";
@Component({
selector: "auth-two-factor-icon",
templateUrl: "./two-factor-icon.component.html",
})
export class TwoFactorIconComponent {
@Input() provider: any;
@Input() name: string;
protected readonly Icons = {
TOTPIcon,
EmailIcon,
WebAuthnIcon,
RecoveryCodeIcon,
};
constructor() {}
}

View File

@ -0,0 +1,44 @@
import { svgIcon } from "@bitwarden/components";
export const EmailIcon = svgIcon`
<svg
xmlns="http://www.w3.org/2000/svg"
width="67"
height="64"
fill="none"
class="tw-text-primary-600"
role="img"
aria-label="[title]"
>
<title>Email</title>
<path
stroke="currentColor"
stroke-width="2"
d="m9.28 19.155-5.848 4.363a4 4 0 0 0-1.608 3.206V59a4 4 0 0 0 4 4h56.044a4 4 0 0 0 4-4V26.742a4 4 0 0 0-1.63-3.223L58.3 19.155M42.438 7.49l-6.442-4.736a4 4 0 0 0-4.762.017l-6.324 4.72"
/>
<path
stroke="currentColor"
stroke-linecap="round"
stroke-width="2"
d="M58.373 30.978V9.473a2 2 0 0 0-2-2H11.318a2 2 0 0 0-2 2v21.505"
/>
<path
stroke="currentColor"
stroke-width="2"
d="M64.504 61.637 43.35 42.107a6 6 0 0 0-4.07-1.59H27.421a6 6 0 0 0-4.175 1.69l-20.06 19.43"
/>
<path
stroke="currentColor"
stroke-linecap="round"
stroke-width="2"
d="m65.181 27.239-22.81 13.623M2.51 27.24l22.81 13.622"
/>
<rect width="35" height="12" x="16.324" y="17.5" stroke="currentColor" rx="6" />
<circle cx="21.324" cy="23.5" r="1.5" fill="currentColor" />
<circle cx="31.324" cy="23.5" r="1.5" fill="currentColor" />
<circle cx="41.324" cy="23.5" r="1.5" fill="currentColor" />
<circle cx="26.324" cy="23.5" r="1.5" fill="currentColor" />
<circle cx="36.324" cy="23.5" r="1.5" fill="currentColor" />
<circle cx="46.324" cy="23.5" r="1.5" fill="currentColor" />
</svg>
`;

View File

@ -0,0 +1,51 @@
import { svgIcon } from "@bitwarden/components";
export const RecoveryCodeIcon = svgIcon`
<svg
xmlns="http://www.w3.org/2000/svg"
alt="rc logo"
width="76"
height="63"
fill="none"
class="tw-text-primary-600"
role="img"
aria-label="[title]"
>
<title>Recovery Code</title>
<rect
width="49.459"
height="17.255"
x="1"
y="-1"
stroke="currentColor"
stroke-width="2"
rx="8.627"
transform="matrix(-1 0 0 1 52.15 38.12)"
/>
<path
fill="currentColor"
d="M7.742 19.337a1 1 0 0 1 1.635-1.152l-1.635 1.152Zm7.499 8.895.576.817a1 1 0 0 1-1.393-.24l.817-.577Zm8.895-7.498a1 1 0 1 1 1.152 1.634l-1.152-1.634Zm44.129 29.953-.776-.631.776.631ZM63.942 8.483l.631-.775-.631.775Zm-42.205 4.323.776.631-.776-.631Zm22.266 49.925a1 1 0 1 1 .063-1.999l-.063 2ZM16.358 27.183a1 1 0 1 1-1.975-.313l1.975.313Zm-6.981-8.998 6.681 9.47-1.634 1.153-6.682-9.47 1.635-1.154Zm5.287 9.23 9.472-6.681 1.152 1.634-9.47 6.681-1.154-1.634ZM67.49 50.056c10.112-12.42 8.241-30.685-4.179-40.797l1.263-1.551C77.85 18.517 79.85 38.042 69.04 51.318l-1.55-1.262ZM63.31 9.259C50.89-.853 32.625 1.018 22.513 13.437l-1.551-1.262C31.772-1.102 51.297-3.102 64.573 7.708l-1.263 1.55ZM44.066 60.732c8.732.275 17.484-3.381 23.423-10.676l1.551 1.263c-6.35 7.799-15.708 11.706-25.037 11.412l.063-1.999ZM22.513 13.437a28.861 28.861 0 0 0-6.155 13.746l-1.975-.313a30.861 30.861 0 0 1 6.579-14.695l1.551 1.262Z"
/>
<path
stroke="currentColor"
stroke-linejoin="round"
stroke-width="2"
d="M36.59 25.167v-5.445c0-4.021 3.806-7.267 8.475-7.267s8.475 3.264 8.475 7.267v5.445"
/>
<path
stroke="currentColor"
stroke-width="2"
d="M32.353 37.345v-6.098a6 6 0 0 1 6-6h13.424a6 6 0 0 1 6 6v9.187a6 6 0 0 1-6 6h-.601"
/>
<path
fill="currentColor"
d="M45.886 35.63c.491-.285.822-.82.822-1.432v-.5c0-.913-.736-1.653-1.643-1.653-.908 0-1.643.74-1.643 1.654v.499c0 .612.33 1.146.82 1.432v1.283c0 .457.368.827.822.827.454 0 .822-.37.822-.827v-1.282Z"
/>
<circle cx="2" cy="2" r="2" fill="currentColor" transform="matrix(-1 0 0 1 46.001 44.148)" />
<circle cx="2" cy="2" r="2" fill="currentColor" transform="matrix(-1 0 0 1 32.001 44.148)" />
<circle cx="2" cy="2" r="2" fill="currentColor" transform="matrix(-1 0 0 1 18.001 44.148)" />
<circle cx="2" cy="2" r="2" fill="currentColor" transform="matrix(-1 0 0 1 39.001 44.148)" />
<circle cx="2" cy="2" r="2" fill="currentColor" transform="matrix(-1 0 0 1 25.001 44.148)" />
<circle cx="2" cy="2" r="2" fill="currentColor" transform="matrix(-1 0 0 1 11.001 44.148)" />
</svg>
`;

View File

@ -0,0 +1,61 @@
import { svgIcon } from "@bitwarden/components";
export const TOTPIcon = svgIcon`
<svg
xmlns="http://www.w3.org/2000/svg"
width="120"
height="62"
fill="none"
class="tw-text-primary-600"
role="img"
aria-label="[title]"
>
<title>TOTP Authenticator</title>
<rect width="35" height="12" x="50.324" y="21.5" stroke="currentColor" rx="6" />
<circle cx="55.324" cy="27.5" r="1.5" fill="currentColor" />
<circle cx="65.324" cy="27.5" r="1.5" fill="currentColor" />
<circle cx="75.324" cy="27.5" r="1.5" fill="currentColor" />
<circle cx="60.324" cy="27.5" r="1.5" fill="currentColor" />
<circle cx="70.324" cy="27.5" r="1.5" fill="currentColor" />
<circle cx="80.324" cy="27.5" r="1.5" fill="currentColor" />
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M52.703 61h34.706"
/>
<path
stroke="currentColor"
stroke-linejoin="round"
stroke-width="2"
d="M63.932 51.166V61M75.16 51.166V61"
/>
<path
stroke="currentColor"
stroke-width="2"
d="M38.952 51.166h64.894a6 6 0 0 0 6-6V7a6 6 0 0 0-6-6h-68a6 6 0 0 0-6 6v7.655"
/>
<path
stroke="currentColor"
d="M38.692 46.517h62.999a4 4 0 0 0 4-4V9.552a4 4 0 0 0-4-4H38.537a4 4 0 0 0-4 4v5.103"
/>
<path
stroke="currentColor"
stroke-linecap="round"
stroke-linejoin="round"
d="M32.284 27.382h11.064l-2.912-2.895M43.348 30.276H32.284l2.912 2.895"
/>
<path
stroke="currentColor"
stroke-width="2"
d="M37.846 27.75V19a4 4 0 0 0-4-4h-18a4 4 0 0 0-4 4v38a4 4 0 0 0 4 4h18a4 4 0 0 0 4-4V30.5"
/>
<path stroke="currentColor" stroke-linecap="round" stroke-width="2" d="M24.806 18.5h.08" />
<path stroke="currentColor" d="M24.846 36a8 8 0 1 0 7.858 6.5" />
<path
fill="currentColor"
d="M21.547 45.36h1.02v-3.64l-1.221.584v-.626l1.215-.575h.657v4.258h1.007v.545h-2.678v-.545ZM25.793 45.358h2.23v.548h-2.948v-.548c.405-.424.76-.799 1.063-1.124a27 27 0 0 0 .627-.687c.216-.263.363-.475.438-.636.076-.164.114-.33.114-.5 0-.27-.08-.48-.24-.633-.158-.153-.376-.23-.653-.23a1.99 1.99 0 0 0-.621.107 3.493 3.493 0 0 0-.69.323v-.658c.224-.106.443-.185.657-.24.217-.053.43-.08.64-.08.475 0 .856.126 1.145.378.29.25.435.578.435.984 0 .207-.049.413-.146.62a3.005 3.005 0 0 1-.468.684c-.122.14-.298.334-.53.581-.23.248-.58.618-1.053 1.11Z"
/>
</svg>
`;

View File

@ -0,0 +1,42 @@
import { svgIcon } from "@bitwarden/components";
export const WebAuthnIcon = svgIcon`
<svg
xmlns="http://www.w3.org/2000/svg"
width="62.176998"
height="60.152"
fill="none"
class="tw-text-primary-600"
role="img"
aria-label="[title]"
>
<title>Webauthn</title>
<g stroke="currentColor" clip-path="url(#a)" transform="translate(-6.081,-1.143)">
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-miterlimit="10"
stroke-width="2"
d="M20.418 33.19c5.614 0 10.42 3.56 12.396 8.533h29.012l5.434 5.522-4.491 4.563h-6.602l-3.413-3.468-3.279 3.24-1.167-1.187-1.303 1.323-3.188-3.24-3.1 3.149H32.86c-1.932 5.065-6.782 8.67-12.44 8.67-7.366 0-13.339-6.069-13.339-13.553 0-7.483 5.928-13.552 13.338-13.552Zm-6.152 16.975c1.841 0 3.368-1.506 3.368-3.422 0-1.871-1.482-3.423-3.368-3.423-1.887 0-3.369 1.506-3.369 3.422 0 1.917 1.527 3.423 3.369 3.423Z"
/>
<path
stroke-linecap="round"
d="M59.78 44.722H36.32M19.99 36.722c4.036 0 7.569 2.405 9.51 6"
/>
<circle
cx="12.24"
cy="12.24"
r="12.24"
stroke-width="2"
transform="matrix(-1 0 0 1 50.6 2.143)"
/>
<path
stroke-width="2"
d="M22.753 33.423c3.836-4.174 9.41-6.8 15.615-6.8 9.698 0 17.857 6.417 20.243 15.13"
/>
</g>
<defs>
<clipPath id="a"><path fill="#fff" d="M68.5.62H.5v61h68z" /></clipPath>
</defs>
</svg>
`;

View File

@ -17,6 +17,7 @@ import {
DialogModule,
FormFieldModule,
IconButtonModule,
IconModule,
LinkModule,
MenuModule,
RadioButtonModule,
@ -26,6 +27,7 @@ import {
TypographyModule,
} from "@bitwarden/components";
import { TwoFactorIconComponent } from "./auth/components/two-factor-icon.component";
import { CalloutComponent } from "./components/callout.component";
import { A11yInvalidDirective } from "./directives/a11y-invalid.directive";
import { A11yTitleDirective } from "./directives/a11y-title.directive";
@ -74,6 +76,7 @@ import { IconComponent } from "./vault/components/icon.component";
TableModule,
MenuModule,
IconButtonModule,
IconModule,
LinkModule,
],
declarations: [
@ -109,6 +112,7 @@ import { IconComponent } from "./vault/components/icon.component";
ManageTaxInformationComponent,
SelectPaymentMethodComponent,
VerifyBankAccountComponent,
TwoFactorIconComponent,
],
exports: [
A11yInvalidDirective,
@ -144,6 +148,7 @@ import { IconComponent } from "./vault/components/icon.component";
ManageTaxInformationComponent,
SelectPaymentMethodComponent,
VerifyBankAccountComponent,
TwoFactorIconComponent,
],
providers: [
CreditCardNumberPipe,

View File

@ -18,7 +18,7 @@ export const TwoFactorProviders: Partial<Record<TwoFactorProviderType, TwoFactor
name: null as string,
description: null as string,
priority: 1,
sort: 1,
sort: 2,
premium: false,
},
[TwoFactorProviderType.Yubikey]: {
@ -26,7 +26,7 @@ export const TwoFactorProviders: Partial<Record<TwoFactorProviderType, TwoFactor
name: null as string,
description: null as string,
priority: 3,
sort: 2,
sort: 4,
premium: true,
},
[TwoFactorProviderType.Duo]: {
@ -34,7 +34,7 @@ export const TwoFactorProviders: Partial<Record<TwoFactorProviderType, TwoFactor
name: "Duo",
description: null as string,
priority: 2,
sort: 3,
sort: 5,
premium: true,
},
[TwoFactorProviderType.OrganizationDuo]: {
@ -42,7 +42,7 @@ export const TwoFactorProviders: Partial<Record<TwoFactorProviderType, TwoFactor
name: "Duo (Organization)",
description: null as string,
priority: 10,
sort: 4,
sort: 6,
premium: false,
},
[TwoFactorProviderType.Email]: {
@ -50,7 +50,7 @@ export const TwoFactorProviders: Partial<Record<TwoFactorProviderType, TwoFactor
name: null as string,
description: null as string,
priority: 0,
sort: 6,
sort: 1,
premium: false,
},
[TwoFactorProviderType.WebAuthn]: {
@ -58,7 +58,7 @@ export const TwoFactorProviders: Partial<Record<TwoFactorProviderType, TwoFactor
name: null as string,
description: null as string,
priority: 4,
sort: 5,
sort: 3,
premium: false,
},
};
@ -97,14 +97,14 @@ export class TwoFactorService implements TwoFactorServiceAbstraction {
init() {
TwoFactorProviders[TwoFactorProviderType.Email].name = this.i18nService.t("emailTitle");
TwoFactorProviders[TwoFactorProviderType.Email].description = this.i18nService.t("emailDesc");
TwoFactorProviders[TwoFactorProviderType.Email].description = this.i18nService.t("emailDescV2");
TwoFactorProviders[TwoFactorProviderType.Authenticator].name =
this.i18nService.t("authenticatorAppTitle");
TwoFactorProviders[TwoFactorProviderType.Authenticator].description =
this.i18nService.t("authenticatorAppDesc");
this.i18nService.t("authenticatorAppDescV2");
TwoFactorProviders[TwoFactorProviderType.Duo].description = this.i18nService.t("duoDesc");
TwoFactorProviders[TwoFactorProviderType.Duo].description = this.i18nService.t("duoDescV2");
TwoFactorProviders[TwoFactorProviderType.OrganizationDuo].name =
"Duo (" + this.i18nService.t("organization") + ")";
@ -115,7 +115,7 @@ export class TwoFactorService implements TwoFactorServiceAbstraction {
TwoFactorProviders[TwoFactorProviderType.WebAuthn].description =
this.i18nService.t("webAuthnDesc");
TwoFactorProviders[TwoFactorProviderType.Yubikey].name = this.i18nService.t("yubiKeyTitle");
TwoFactorProviders[TwoFactorProviderType.Yubikey].name = this.i18nService.t("yubiKeyTitleV2");
TwoFactorProviders[TwoFactorProviderType.Yubikey].description =
this.i18nService.t("yubiKeyDesc");
}