mirror of
https://github.com/zitadel/zitadel.git
synced 2025-02-28 21:37:24 +00:00
feat(console): add otp sms
and otp email
as factor (#6343)
* cli, core * material cdk * schematics * chore(deps-dev): bump eslint from 8.40.0 to 8.44.0 in /console (#6127) Bumps [eslint](https://github.com/eslint/eslint) from 8.40.0 to 8.44.0. - [Release notes](https://github.com/eslint/eslint/releases) - [Changelog](https://github.com/eslint/eslint/blob/main/CHANGELOG.md) - [Commits](https://github.com/eslint/eslint/compare/v8.40.0...v8.44.0) --- updated-dependencies: - dependency-name: eslint dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * npm * feat: add otp sms button * lock * rm package-lock * prompt to setup sms otp on verify * cli, core * material, cdk * schematics * otp email * show type * show type on mgmt page * disable selection on add * rename totp * fix totp i18n * directly use data, fix styles * sms req * fix type check * fix delete * rm comment --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Livio Spring <livio.a@gmail.com>
This commit is contained in:
parent
26b28ed2af
commit
a262595fc2
0
console/package-lock.json
generated
0
console/package-lock.json
generated
@ -12,18 +12,18 @@
|
|||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "^16.1.2",
|
"@angular/animations": "^16.2.0",
|
||||||
"@angular/cdk": "^16.1.2",
|
"@angular/cdk": "^16.2.0",
|
||||||
"@angular/common": "^16.1.2",
|
"@angular/common": "^16.2.0",
|
||||||
"@angular/compiler": "^16.1.2",
|
"@angular/compiler": "^16.2.0",
|
||||||
"@angular/core": "^16.1.2",
|
"@angular/core": "^16.2.0",
|
||||||
"@angular/forms": "^16.1.2",
|
"@angular/forms": "^16.2.0",
|
||||||
"@angular/material": "^16.1.2",
|
"@angular/material": "^16.2.0",
|
||||||
"@angular/material-moment-adapter": "^16.1.2",
|
"@angular/material-moment-adapter": "^16.2.0",
|
||||||
"@angular/platform-browser": "^16.1.2",
|
"@angular/platform-browser": "^16.2.0",
|
||||||
"@angular/platform-browser-dynamic": "^16.1.2",
|
"@angular/platform-browser-dynamic": "^16.2.0",
|
||||||
"@angular/router": "^16.1.2",
|
"@angular/router": "^16.2.0",
|
||||||
"@angular/service-worker": "^16.1.2",
|
"@angular/service-worker": "^16.2.0",
|
||||||
"@ctrl/ngx-codemirror": "^6.1.0",
|
"@ctrl/ngx-codemirror": "^6.1.0",
|
||||||
"@grpc/grpc-js": "^1.8.14",
|
"@grpc/grpc-js": "^1.8.14",
|
||||||
"@ngx-translate/core": "^14.0.0",
|
"@ngx-translate/core": "^14.0.0",
|
||||||
@ -33,7 +33,7 @@
|
|||||||
"codemirror": "^5.65.8",
|
"codemirror": "^5.65.8",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"file-saver": "^2.0.5",
|
"file-saver": "^2.0.5",
|
||||||
"flag-icons": "^6.6.6",
|
"flag-icons": "^6.7.0",
|
||||||
"google-proto-files": "^3.0.3",
|
"google-proto-files": "^3.0.3",
|
||||||
"google-protobuf": "^3.21.2",
|
"google-protobuf": "^3.21.2",
|
||||||
"grpc-web": "^1.4.1",
|
"grpc-web": "^1.4.1",
|
||||||
@ -47,19 +47,19 @@
|
|||||||
"tinycolor2": "^1.6.0",
|
"tinycolor2": "^1.6.0",
|
||||||
"tslib": "^2.4.1",
|
"tslib": "^2.4.1",
|
||||||
"uuid": "^9.0.0",
|
"uuid": "^9.0.0",
|
||||||
"zone.js": "~0.13.0"
|
"zone.js": "~0.13.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular-devkit/build-angular": "^16.1.1",
|
"@angular-devkit/build-angular": "^16.2.0",
|
||||||
"@angular-eslint/builder": "16.0.1",
|
"@angular-eslint/builder": "16.1.0",
|
||||||
"@angular-eslint/eslint-plugin": "16.0.1",
|
"@angular-eslint/eslint-plugin": "16.1.0",
|
||||||
"@angular-eslint/eslint-plugin-template": "16.0.1",
|
"@angular-eslint/eslint-plugin-template": "16.1.0",
|
||||||
"@angular-eslint/schematics": "16.0.1",
|
"@angular-eslint/schematics": "16.1.0",
|
||||||
"@angular-eslint/template-parser": "16.0.1",
|
"@angular-eslint/template-parser": "16.1.0",
|
||||||
"@angular/cli": "^16.1.1",
|
"@angular/cli": "^16.2.0",
|
||||||
"@angular/compiler-cli": "^16.1.2",
|
"@angular/compiler-cli": "^16.2.0",
|
||||||
"@angular/language-service": "^16.1.2",
|
"@angular/language-service": "^16.2.0",
|
||||||
"@bufbuild/buf": "^1.18.0-1",
|
"@bufbuild/buf": "^1.23.1",
|
||||||
"@types/file-saver": "^2.0.2",
|
"@types/file-saver": "^2.0.2",
|
||||||
"@types/google-protobuf": "^3.15.3",
|
"@types/google-protobuf": "^3.15.3",
|
||||||
"@types/jasmine": "~4.3.3",
|
"@types/jasmine": "~4.3.3",
|
||||||
@ -68,21 +68,21 @@
|
|||||||
"@types/node": "^18.15.11",
|
"@types/node": "^18.15.11",
|
||||||
"@types/opentype.js": "^1.3.4",
|
"@types/opentype.js": "^1.3.4",
|
||||||
"@types/qrcode": "^1.5.0",
|
"@types/qrcode": "^1.5.0",
|
||||||
"@types/uuid": "^9.0.1",
|
"@types/uuid": "^9.0.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.59.11",
|
"@typescript-eslint/eslint-plugin": "^5.59.11",
|
||||||
"@typescript-eslint/parser": "^5.59.5",
|
"@typescript-eslint/parser": "^5.60.1",
|
||||||
"codelyzer": "^6.0.2",
|
"codelyzer": "^6.0.2",
|
||||||
"eslint": "^8.39.0",
|
"eslint": "^8.44.0",
|
||||||
"jasmine-core": "~4.6.0",
|
"jasmine-core": "~4.6.0",
|
||||||
"jasmine-spec-reporter": "~7.0.0",
|
"jasmine-spec-reporter": "~7.0.0",
|
||||||
"karma": "^6.4.2",
|
"karma": "^6.4.2",
|
||||||
"karma-chrome-launcher": "^3.2.0",
|
"karma-chrome-launcher": "^3.2.0",
|
||||||
"karma-coverage-istanbul-reporter": "^3.0.3",
|
"karma-coverage-istanbul-reporter": "^3.0.3",
|
||||||
"karma-jasmine": "^5.1.0",
|
"karma-jasmine": "^5.1.0",
|
||||||
"karma-jasmine-html-reporter": "^2.0.0",
|
"karma-jasmine-html-reporter": "^2.1.0",
|
||||||
"prettier": "^2.8.7",
|
"prettier": "^2.8.7",
|
||||||
"prettier-plugin-organize-imports": "^3.2.2",
|
"prettier-plugin-organize-imports": "^3.2.2",
|
||||||
"protractor": "~7.0.0",
|
"protractor": "~7.0.0",
|
||||||
"typescript": "^4.9.5"
|
"typescript": "^4.9.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
<span class="title" mat-dialog-title>{{ data.titleKey | translate : data.titleParam }}</span>
|
||||||
|
<div mat-dialog-content>
|
||||||
|
<div class="icon-wrapper" *ngIf="data.icon">
|
||||||
|
<i class="icon {{ data.icon }}"></i>
|
||||||
|
</div>
|
||||||
|
<p class="desc cnsl-secondary-text">{{ data.descriptionKey | translate : data.descriptionParam }}</p>
|
||||||
|
|
||||||
|
<cnsl-info-section *ngIf="data.infoSectionKey" [type]="InfoSectionType.INFO">{{
|
||||||
|
data.warnSectionKey | translate
|
||||||
|
}}</cnsl-info-section>
|
||||||
|
|
||||||
|
<p *ngIf="data.hintKey" class="desc cnsl-secondary-text">{{ data.hintKey | translate : { value: data.confirmation } }}</p>
|
||||||
|
|
||||||
|
<cnsl-form-field *ngIf="data.confirmation && data.confirmationKey" class="formfield">
|
||||||
|
<cnsl-label>{{ data.confirmationKey | translate : { value: data.confirmation } }}</cnsl-label>
|
||||||
|
<input cnslInput [(ngModel)]="confirm" data-e2e="confirm-dialog-input" />
|
||||||
|
</cnsl-form-field>
|
||||||
|
</div>
|
||||||
|
<div mat-dialog-actions class="action">
|
||||||
|
<button *ngIf="data.cancelKey" mat-stroked-button (click)="closeDialog()">
|
||||||
|
{{ data.cancelKey | translate }}
|
||||||
|
</button>
|
||||||
|
<span class="fill-space"></span>
|
||||||
|
<button
|
||||||
|
color="primary"
|
||||||
|
[disabled]="data.confirmation && confirm !== data.confirmation"
|
||||||
|
mat-raised-button
|
||||||
|
class="ok-button"
|
||||||
|
(click)="closeDialogWithSuccess()"
|
||||||
|
data-e2e="confirm-dialog-button"
|
||||||
|
>
|
||||||
|
{{ data.confirmKey | translate }}
|
||||||
|
</button>
|
||||||
|
</div>
|
@ -0,0 +1,36 @@
|
|||||||
|
.title {
|
||||||
|
font-size: 1.2rem;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.icon-wrapper {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 1rem;
|
||||||
|
margin: 1rem;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.icon {
|
||||||
|
font-size: 3rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.desc {
|
||||||
|
font-size: 0.9rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.action {
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
button {
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ok-button {
|
||||||
|
margin-left: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fill-space {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { InfoDialogComponent } from './info-dialog.component';
|
||||||
|
|
||||||
|
describe('InfoDialogComponent', () => {
|
||||||
|
let component: InfoDialogComponent;
|
||||||
|
let fixture: ComponentFixture<InfoDialogComponent>;
|
||||||
|
|
||||||
|
beforeEach(waitForAsync(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
declarations: [InfoDialogComponent],
|
||||||
|
}).compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(InfoDialogComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
26
console/src/app/modules/info-dialog/info-dialog.component.ts
Normal file
26
console/src/app/modules/info-dialog/info-dialog.component.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import { Component, Inject } from '@angular/core';
|
||||||
|
import {
|
||||||
|
MatLegacyDialogRef as MatDialogRef,
|
||||||
|
MAT_LEGACY_DIALOG_DATA as MAT_DIALOG_DATA,
|
||||||
|
} from '@angular/material/legacy-dialog';
|
||||||
|
|
||||||
|
import { InfoSectionType } from '../info-section/info-section.component';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'cnsl-info-dialog',
|
||||||
|
templateUrl: './info-dialog.component.html',
|
||||||
|
styleUrls: ['./info-dialog.component.scss'],
|
||||||
|
})
|
||||||
|
export class InfoDialogComponent {
|
||||||
|
public confirm: string = '';
|
||||||
|
InfoSectionType: any = InfoSectionType;
|
||||||
|
constructor(public dialogRef: MatDialogRef<InfoDialogComponent>, @Inject(MAT_DIALOG_DATA) public data: any) {}
|
||||||
|
|
||||||
|
public closeDialog(): void {
|
||||||
|
this.dialogRef.close(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public closeDialogWithSuccess(): void {
|
||||||
|
this.dialogRef.close(true);
|
||||||
|
}
|
||||||
|
}
|
15
console/src/app/modules/info-dialog/info-dialog.module.ts
Normal file
15
console/src/app/modules/info-dialog/info-dialog.module.ts
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
import { FormsModule } from '@angular/forms';
|
||||||
|
import { MatLegacyButtonModule as MatButtonModule } from '@angular/material/legacy-button';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
import { InfoSectionModule } from '../info-section/info-section.module';
|
||||||
|
import { InputModule } from '../input/input.module';
|
||||||
|
import { InfoDialogComponent } from './info-dialog.component';
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [InfoDialogComponent],
|
||||||
|
imports: [CommonModule, FormsModule, TranslateModule, InfoSectionModule, MatButtonModule, InputModule],
|
||||||
|
})
|
||||||
|
export class InfoDialogModule {}
|
@ -31,7 +31,6 @@
|
|||||||
|
|
||||||
.info-section-content {
|
.info-section-content {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
padding: 0.25rem 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.info {
|
&.info {
|
||||||
|
@ -7,27 +7,130 @@
|
|||||||
|
|
||||||
<div class="type-selection">
|
<div class="type-selection">
|
||||||
<button
|
<button
|
||||||
mat-raised-button
|
mat-stroked-button
|
||||||
color="primary"
|
|
||||||
[disabled]="data.otpDisabled$ | async"
|
[disabled]="data.otpDisabled$ | async"
|
||||||
(click)="selectType(AuthFactorType.OTP)"
|
(click)="selectType(AuthFactorType.OTP)"
|
||||||
data-e2e="add-factor-otp"
|
data-e2e="add-factor-otp"
|
||||||
>
|
>
|
||||||
<div class="otp-btn">
|
<div class="otp-btn">
|
||||||
<mat-icon class="icon" svgIcon="mdi_radar"></mat-icon>
|
<div class="icon-row">
|
||||||
|
<svg
|
||||||
|
class="authenticator-logo"
|
||||||
|
version="1.1"
|
||||||
|
baseProfile="basic"
|
||||||
|
id="Layer_1"
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
|
x="0px"
|
||||||
|
y="0px"
|
||||||
|
viewBox="0 0 512 512"
|
||||||
|
xml:space="preserve"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
fill="#1A73E8"
|
||||||
|
d="M440,255.99997v0.00006C440,273.12085,426.12085,287,409.00003,287H302l-46-93.01001l49.6507-85.9951
|
||||||
|
c8.56021-14.82629,27.51834-19.9065,42.34518-11.34724l0.00586,0.0034c14.82776,8.55979,19.90875,27.51928,11.34857,42.34682
|
||||||
|
L309.70001,225h99.30002C426.12085,225,440,238.87917,440,255.99997z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
fill="#EA4335"
|
||||||
|
d="M348.00174,415.34897l-0.00586,0.00339c-14.82684,8.55927-33.78497,3.47903-42.34518-11.34723L256,318.01001
|
||||||
|
l-49.65065,85.99509c-8.5602,14.82629-27.51834,19.90652-42.34517,11.34729l-0.00591-0.00342
|
||||||
|
c-14.82777-8.55978-19.90875-27.51929-11.34859-42.34683L202.29999,287L256,285l53.70001,2l49.6503,86.00214
|
||||||
|
C367.91049,387.82968,362.8295,406.78918,348.00174,415.34897z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
fill="#FBBC04"
|
||||||
|
d="M256,193.98999L242,232l-39.70001-7l-49.6503-86.00212
|
||||||
|
c-8.56017-14.82755-3.47919-33.78705,11.34859-42.34684l0.00591-0.00341c14.82683-8.55925,33.78497-3.47903,42.34517,11.34726
|
||||||
|
L256,193.98999z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
fill="#34A853"
|
||||||
|
d="M248,225l-36,62H102.99997C85.87916,287,72,273.12085,72,256.00003v-0.00006
|
||||||
|
C72,238.87917,85.87916,225,102.99997,225H248z"
|
||||||
|
/>
|
||||||
|
<polygon fill="#185DB7" points="309.70001,287 202.29999,287 256,193.98999 " />
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
<span>{{ 'USER.MFA.OTP' | translate }}</span>
|
<span>{{ 'USER.MFA.OTP' | translate }}</span>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
<button mat-raised-button color="primary" (click)="selectType(AuthFactorType.U2F)">
|
<button mat-stroked-button (click)="selectType(AuthFactorType.U2F)">
|
||||||
<div class="u2f-btn">
|
<div class="u2f-btn">
|
||||||
<div class="icon-row">
|
<div class="icon-row">
|
||||||
<i matTooltip="Fingerprint" class="las la-fingerprint"></i>
|
<svg
|
||||||
<i matTooltip="Security Key" class="lab la-usb"></i>
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
<mat-icon matTooltip="NFC">nfc</mat-icon>
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke-width="1.5"
|
||||||
|
stroke="currentColor"
|
||||||
|
class="fingerprint"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
d="M7.864 4.243A7.5 7.5 0 0119.5 10.5c0 2.92-.556 5.709-1.568 8.268M5.742 6.364A7.465 7.465 0 004.5 10.5a7.464 7.464 0 01-1.15 3.993m1.989 3.559A11.209 11.209 0 008.25 10.5a3.75 3.75 0 117.5 0c0 .527-.021 1.049-.064 1.565M12 10.5a14.94 14.94 0 01-3.6 9.75m6.633-4.596a18.666 18.666 0 01-2.485 5.33"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<span>{{ 'USER.MFA.U2F' | translate }}</span>
|
<span>{{ 'USER.MFA.U2F' | translate }}</span>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
[disabled]="!data.phoneVerified || (data.otpSmsDisabled$ | async)"
|
||||||
|
mat-stroked-button
|
||||||
|
(click)="selectType(AuthFactorType.OTPSMS)"
|
||||||
|
>
|
||||||
|
<div class="otp-btn">
|
||||||
|
<div class="col">
|
||||||
|
<div class="row">
|
||||||
|
<div class="icon-row">
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke-width="1.5"
|
||||||
|
stroke="currentColor"
|
||||||
|
class="sms"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
d="M10.5 1.5H8.25A2.25 2.25 0 006 3.75v16.5a2.25 2.25 0 002.25 2.25h7.5A2.25 2.25 0 0018 20.25V3.75a2.25 2.25 0 00-2.25-2.25H13.5m-3 0V3h3V1.5m-3 0h3m-3 18.75h3"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<span>{{ 'USER.MFA.OTPSMS' | translate }}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<cnsl-info-section class="info" [type]="InfoSectionType.ALERT" *ngIf="!data.phoneVerified"
|
||||||
|
><span>{{ 'USER.MFA.OTPSMSPHONEMUSTBEVERIFIED' | translate }}</span></cnsl-info-section
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
<button [disabled]="data.otpEmailDisabled$ | async" mat-stroked-button (click)="selectType(AuthFactorType.OTPEMAIL)">
|
||||||
|
<div class="otp-btn">
|
||||||
|
<div class="icon-row">
|
||||||
|
<svg
|
||||||
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
|
fill="none"
|
||||||
|
viewBox="0 0 24 24"
|
||||||
|
stroke-width="1.5"
|
||||||
|
stroke="currentColor"
|
||||||
|
class="email"
|
||||||
|
>
|
||||||
|
<path
|
||||||
|
stroke-linecap="round"
|
||||||
|
stroke-linejoin="round"
|
||||||
|
d="M21.75 6.75v10.5a2.25 2.25 0 01-2.25 2.25h-15a2.25 2.25 0 01-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25m19.5 0v.243a2.25 2.25 0 01-1.07 1.916l-7.5 4.615a2.25 2.25 0 01-2.36 0L3.32 8.91a2.25 2.25 0 01-1.07-1.916V6.75"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
<span>{{ 'USER.MFA.OTPEMAIL' | translate }}</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
|
@ -1,21 +1,67 @@
|
|||||||
|
.desc {
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.type-selection {
|
.type-selection {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
margin: 0 -0.5rem;
|
margin: 0 -0.5rem;
|
||||||
|
|
||||||
.otp-btn,
|
.otp-btn,
|
||||||
.u2f-btn {
|
.u2f-btn {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-height: 100px;
|
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: row;
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
margin: 1rem;
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
white-space: normal;
|
||||||
|
line-height: 1.5rem;
|
||||||
|
padding: 0.5rem 0;
|
||||||
|
|
||||||
|
.col {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
.info {
|
||||||
|
margin-left: calc(40px + 1rem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.authenticator-logo {
|
||||||
|
height: 40px;
|
||||||
|
width: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
white-space: normal;
|
||||||
|
}
|
||||||
|
|
||||||
.icon-row {
|
.icon-row {
|
||||||
|
height: 40px;
|
||||||
|
width: 40px;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-right: 1rem;
|
||||||
|
|
||||||
|
.sms,
|
||||||
|
.email,
|
||||||
|
.fingerprint {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.25rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
text-align: start;
|
||||||
|
flex: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,12 +8,15 @@ import { take } from 'rxjs/operators';
|
|||||||
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
||||||
import { ToastService } from 'src/app/services/toast.service';
|
import { ToastService } from 'src/app/services/toast.service';
|
||||||
|
|
||||||
|
import { InfoSectionType } from 'src/app/modules/info-section/info-section.component';
|
||||||
import { _base64ToArrayBuffer } from '../../u2f-util';
|
import { _base64ToArrayBuffer } from '../../u2f-util';
|
||||||
import { _arrayBufferToBase64 } from '../u2f_util';
|
import { _arrayBufferToBase64 } from '../u2f_util';
|
||||||
|
|
||||||
export enum AuthFactorType {
|
export enum AuthFactorType {
|
||||||
OTP,
|
OTP,
|
||||||
U2F,
|
U2F,
|
||||||
|
OTPSMS,
|
||||||
|
OTPEMAIL,
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -32,10 +35,13 @@ export class AuthFactorDialogComponent {
|
|||||||
public u2fLoading: boolean = false;
|
public u2fLoading: boolean = false;
|
||||||
public u2fError: string = '';
|
public u2fError: string = '';
|
||||||
|
|
||||||
|
public phoneVerified: boolean = false;
|
||||||
|
|
||||||
AuthFactorType: any = AuthFactorType;
|
AuthFactorType: any = AuthFactorType;
|
||||||
selectedType!: AuthFactorType;
|
selectedType!: AuthFactorType;
|
||||||
|
|
||||||
public copied: string = '';
|
public copied: string = '';
|
||||||
|
public InfoSectionType: any = InfoSectionType;
|
||||||
constructor(
|
constructor(
|
||||||
private authService: GrpcAuthService,
|
private authService: GrpcAuthService,
|
||||||
private toast: ToastService,
|
private toast: ToastService,
|
||||||
@ -52,18 +58,19 @@ export class AuthFactorDialogComponent {
|
|||||||
this.selectedType = type;
|
this.selectedType = type;
|
||||||
|
|
||||||
if (type === AuthFactorType.OTP) {
|
if (type === AuthFactorType.OTP) {
|
||||||
this.authService.addMyMultiFactorOTP().then(
|
this.authService
|
||||||
(otpresp) => {
|
.addMyMultiFactorOTP()
|
||||||
|
.then((otpresp) => {
|
||||||
this.otpurl = otpresp.url;
|
this.otpurl = otpresp.url;
|
||||||
this.otpsecret = otpresp.secret;
|
this.otpsecret = otpresp.secret;
|
||||||
},
|
})
|
||||||
(error) => {
|
.catch((error) => {
|
||||||
this.toast.showError(error);
|
this.toast.showError(error);
|
||||||
},
|
});
|
||||||
);
|
|
||||||
} else if (type === AuthFactorType.U2F) {
|
} else if (type === AuthFactorType.U2F) {
|
||||||
this.authService.addMyMultiFactorU2F().then(
|
this.authService
|
||||||
(u2fresp) => {
|
.addMyMultiFactorU2F()
|
||||||
|
.then((u2fresp) => {
|
||||||
if (u2fresp.key) {
|
if (u2fresp.key) {
|
||||||
const credOptions: CredentialCreationOptions = JSON.parse(atob(u2fresp.key?.publicKey as string));
|
const credOptions: CredentialCreationOptions = JSON.parse(atob(u2fresp.key?.publicKey as string));
|
||||||
|
|
||||||
@ -79,11 +86,42 @@ export class AuthFactorDialogComponent {
|
|||||||
this.u2fCredentialOptions = credOptions;
|
this.u2fCredentialOptions = credOptions;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
})
|
||||||
(error) => {
|
.catch((error) => {
|
||||||
this.toast.showError(error);
|
this.toast.showError(error);
|
||||||
},
|
});
|
||||||
);
|
} else if (type === AuthFactorType.OTPSMS) {
|
||||||
|
this.authService
|
||||||
|
.addMyAuthFactorOTPSMS()
|
||||||
|
.then(() => {
|
||||||
|
this.dialogRef.close(true);
|
||||||
|
this.translate
|
||||||
|
.get('USER.MFA.OTPSMSSUCCESS')
|
||||||
|
.pipe(take(1))
|
||||||
|
.subscribe((msg) => {
|
||||||
|
this.toast.showInfo(msg);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.dialogRef.close(false);
|
||||||
|
this.toast.showError(error);
|
||||||
|
});
|
||||||
|
} else if (type === AuthFactorType.OTPEMAIL) {
|
||||||
|
this.authService
|
||||||
|
.addMyAuthFactorOTPEmail()
|
||||||
|
.then(() => {
|
||||||
|
this.dialogRef.close(true);
|
||||||
|
this.translate
|
||||||
|
.get('USER.MFA.OTPEMAILSUCCESS')
|
||||||
|
.pipe(take(1))
|
||||||
|
.subscribe((msg) => {
|
||||||
|
this.toast.showInfo(msg);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.dialogRef.close(false);
|
||||||
|
this.toast.showError(error);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,7 +115,11 @@
|
|||||||
|
|
||||||
<cnsl-auth-passwordless *ngIf="user" #mfaComponent></cnsl-auth-passwordless>
|
<cnsl-auth-passwordless *ngIf="user" #mfaComponent></cnsl-auth-passwordless>
|
||||||
|
|
||||||
<cnsl-auth-user-mfa *ngIf="user" #mfaComponent></cnsl-auth-user-mfa>
|
<cnsl-auth-user-mfa
|
||||||
|
[phoneVerified]="user.human?.phone?.isPhoneVerified ?? false"
|
||||||
|
*ngIf="user"
|
||||||
|
#mfaComponent
|
||||||
|
></cnsl-auth-user-mfa>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
<ng-container *ngIf="currentSetting === 'grants'">
|
<ng-container *ngIf="currentSetting === 'grants'">
|
||||||
|
@ -9,6 +9,7 @@ import { Buffer } from 'buffer';
|
|||||||
import { Subscription, take } from 'rxjs';
|
import { Subscription, take } from 'rxjs';
|
||||||
import { ChangeType } from 'src/app/modules/changes/changes.component';
|
import { ChangeType } from 'src/app/modules/changes/changes.component';
|
||||||
import { phoneValidator, requiredValidator } from 'src/app/modules/form-field/validators/validators';
|
import { phoneValidator, requiredValidator } from 'src/app/modules/form-field/validators/validators';
|
||||||
|
import { InfoDialogComponent } from 'src/app/modules/info-dialog/info-dialog.component';
|
||||||
import { MetadataDialogComponent } from 'src/app/modules/metadata/metadata-dialog/metadata-dialog.component';
|
import { MetadataDialogComponent } from 'src/app/modules/metadata/metadata-dialog/metadata-dialog.component';
|
||||||
import { PolicyComponentServiceType } from 'src/app/modules/policies/policy-component-types.enum';
|
import { PolicyComponentServiceType } from 'src/app/modules/policies/policy-component-types.enum';
|
||||||
import { SidenavSetting } from 'src/app/modules/sidenav/sidenav.component';
|
import { SidenavSetting } from 'src/app/modules/sidenav/sidenav.component';
|
||||||
@ -223,12 +224,38 @@ export class AuthUserDetailComponent implements OnDestroy {
|
|||||||
.then(() => {
|
.then(() => {
|
||||||
this.toast.showInfo('USER.TOAST.PHONESAVED', true);
|
this.toast.showInfo('USER.TOAST.PHONESAVED', true);
|
||||||
this.refreshUser();
|
this.refreshUser();
|
||||||
|
this.promptSetupforSMSOTP();
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.toast.showError(error);
|
this.toast.showError(error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public promptSetupforSMSOTP(): void {
|
||||||
|
const dialogRef = this.dialog.open(InfoDialogComponent, {
|
||||||
|
data: {
|
||||||
|
confirmKey: 'ACTIONS.CONTINUE',
|
||||||
|
cancelKey: 'ACTIONS.CANCEL',
|
||||||
|
titleKey: 'USER.MFA.OTPSMS',
|
||||||
|
descriptionKey: 'USER.MFA.SETUPOTPSMSDESCRIPTION',
|
||||||
|
},
|
||||||
|
width: '400px',
|
||||||
|
});
|
||||||
|
|
||||||
|
dialogRef.afterClosed().subscribe((resp) => {
|
||||||
|
if (resp) {
|
||||||
|
this.userService.addMyAuthFactorOTPSMS().then(() => {
|
||||||
|
this.translate
|
||||||
|
.get('USER.MFA.OTPSMSSUCCESS')
|
||||||
|
.pipe(take(1))
|
||||||
|
.subscribe((msg) => {
|
||||||
|
this.toast.showInfo(msg);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public changedLanguage(language: string): void {
|
public changedLanguage(language: string): void {
|
||||||
this.translate.use(language);
|
this.translate.use(language);
|
||||||
}
|
}
|
||||||
|
@ -31,8 +31,10 @@
|
|||||||
<ng-container matColumnDef="type">
|
<ng-container matColumnDef="type">
|
||||||
<th mat-header-cell *matHeaderCellDef>{{ 'USER.MFA.TABLETYPE' | translate }}</th>
|
<th mat-header-cell *matHeaderCellDef>{{ 'USER.MFA.TABLETYPE' | translate }}</th>
|
||||||
<td mat-cell *matCellDef="let mfa">
|
<td mat-cell *matCellDef="let mfa">
|
||||||
<span *ngIf="mfa.otp !== undefined">OTP (One-Time Password)</span>
|
<span *ngIf="mfa.otp !== undefined">TOTP (Time-based One-Time Password)</span>
|
||||||
<span *ngIf="mfa.u2f !== undefined">U2F (Universal 2nd Factor)</span>
|
<span *ngIf="mfa.u2f !== undefined">U2F (Universal 2nd Factor)</span>
|
||||||
|
<span *ngIf="mfa.otpSms !== undefined">One-Time Password SMS</span>
|
||||||
|
<span *ngIf="mfa.otpEmail !== undefined">One-Time Password Email</span>
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
import { Component, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
|
||||||
import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog';
|
import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog';
|
||||||
import { MatLegacyTable as MatTable, MatLegacyTableDataSource as MatTableDataSource } from '@angular/material/legacy-table';
|
import { MatLegacyTable as MatTable, MatLegacyTableDataSource as MatTableDataSource } from '@angular/material/legacy-table';
|
||||||
import { MatSort } from '@angular/material/sort';
|
import { MatSort } from '@angular/material/sort';
|
||||||
@ -32,12 +32,15 @@ export class AuthUserMfaComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
@ViewChild(MatTable) public table!: MatTable<AuthFactor.AsObject>;
|
@ViewChild(MatTable) public table!: MatTable<AuthFactor.AsObject>;
|
||||||
@ViewChild(MatSort) public sort!: MatSort;
|
@ViewChild(MatSort) public sort!: MatSort;
|
||||||
|
@Input() public phoneVerified: boolean = false;
|
||||||
public dataSource: MatTableDataSource<AuthFactor.AsObject> = new MatTableDataSource<AuthFactor.AsObject>([]);
|
public dataSource: MatTableDataSource<AuthFactor.AsObject> = new MatTableDataSource<AuthFactor.AsObject>([]);
|
||||||
|
|
||||||
public AuthFactorState: any = AuthFactorState;
|
public AuthFactorState: any = AuthFactorState;
|
||||||
|
|
||||||
public error: string = '';
|
public error: string = '';
|
||||||
public otpDisabled$ = new BehaviorSubject<boolean>(true);
|
public otpDisabled$ = new BehaviorSubject<boolean>(true);
|
||||||
|
public otpSmsDisabled$ = new BehaviorSubject<boolean>(true);
|
||||||
|
public otpEmailDisabled$ = new BehaviorSubject<boolean>(true);
|
||||||
|
|
||||||
constructor(private service: GrpcAuthService, private toast: ToastService, private dialog: MatDialog) {}
|
constructor(private service: GrpcAuthService, private toast: ToastService, private dialog: MatDialog) {}
|
||||||
|
|
||||||
@ -53,6 +56,9 @@ export class AuthUserMfaComponent implements OnInit, OnDestroy {
|
|||||||
const dialogRef = this.dialog.open(AuthFactorDialogComponent, {
|
const dialogRef = this.dialog.open(AuthFactorDialogComponent, {
|
||||||
data: {
|
data: {
|
||||||
otpDisabled$: this.otpDisabled$,
|
otpDisabled$: this.otpDisabled$,
|
||||||
|
otpSmsDisabled$: this.otpSmsDisabled$,
|
||||||
|
otpEmailDisabled$: this.otpEmailDisabled$,
|
||||||
|
phoneVerified: this.phoneVerified,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -73,12 +79,39 @@ export class AuthUserMfaComponent implements OnInit, OnDestroy {
|
|||||||
if (index === -1) {
|
if (index === -1) {
|
||||||
this.otpDisabled$.next(false);
|
this.otpDisabled$.next(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const sms = list.findIndex((mfa) => mfa.otpSms);
|
||||||
|
if (sms === -1) {
|
||||||
|
this.otpSmsDisabled$.next(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
const email = list.findIndex((mfa) => mfa.otpEmail);
|
||||||
|
if (email === -1) {
|
||||||
|
this.otpEmailDisabled$.next(false);
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.error = error.message;
|
this.error = error.message;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private cleanupList(): void {
|
||||||
|
const totp = this.dataSource.data.findIndex((mfa) => !!mfa.otp);
|
||||||
|
if (totp > -1) {
|
||||||
|
this.dataSource.data.splice(totp, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const sms = this.dataSource.data.findIndex((mfa) => !!mfa.otpSms);
|
||||||
|
if (sms > -1) {
|
||||||
|
this.dataSource.data.splice(sms, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const email = this.dataSource.data.findIndex((mfa) => !!mfa.otpEmail);
|
||||||
|
if (email > -1) {
|
||||||
|
this.dataSource.data.splice(email, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public deleteMFA(factor: AuthFactor.AsObject): void {
|
public deleteMFA(factor: AuthFactor.AsObject): void {
|
||||||
const dialogRef = this.dialog.open(WarnDialogComponent, {
|
const dialogRef = this.dialog.open(WarnDialogComponent, {
|
||||||
data: {
|
data: {
|
||||||
@ -98,10 +131,7 @@ export class AuthUserMfaComponent implements OnInit, OnDestroy {
|
|||||||
.then(() => {
|
.then(() => {
|
||||||
this.toast.showInfo('USER.TOAST.OTPREMOVED', true);
|
this.toast.showInfo('USER.TOAST.OTPREMOVED', true);
|
||||||
|
|
||||||
const index = this.dataSource.data.findIndex((mfa) => !!mfa.otp);
|
this.cleanupList();
|
||||||
if (index > -1) {
|
|
||||||
this.dataSource.data.splice(index, 1);
|
|
||||||
}
|
|
||||||
this.getMFAs();
|
this.getMFAs();
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
@ -113,10 +143,31 @@ export class AuthUserMfaComponent implements OnInit, OnDestroy {
|
|||||||
.then(() => {
|
.then(() => {
|
||||||
this.toast.showInfo('USER.TOAST.U2FREMOVED', true);
|
this.toast.showInfo('USER.TOAST.U2FREMOVED', true);
|
||||||
|
|
||||||
const index = this.dataSource.data.findIndex((mfa) => !!mfa.u2f);
|
this.cleanupList();
|
||||||
if (index > -1) {
|
this.getMFAs();
|
||||||
this.dataSource.data.splice(index, 1);
|
})
|
||||||
}
|
.catch((error) => {
|
||||||
|
this.toast.showError(error);
|
||||||
|
});
|
||||||
|
} else if (factor.otpEmail) {
|
||||||
|
this.service
|
||||||
|
.removeMyAuthFactorOTPEmail()
|
||||||
|
.then(() => {
|
||||||
|
this.toast.showInfo('USER.TOAST.U2FREMOVED', true);
|
||||||
|
|
||||||
|
this.cleanupList();
|
||||||
|
this.getMFAs();
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
this.toast.showError(error);
|
||||||
|
});
|
||||||
|
} else if (factor.otpSms) {
|
||||||
|
this.service
|
||||||
|
.removeMyAuthFactorOTPSMS()
|
||||||
|
.then(() => {
|
||||||
|
this.toast.showInfo('USER.TOAST.U2FREMOVED', true);
|
||||||
|
|
||||||
|
this.cleanupList();
|
||||||
this.getMFAs();
|
this.getMFAs();
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
|
@ -3,6 +3,7 @@ import { MatLegacyDialog as MatDialog } from '@angular/material/legacy-dialog';
|
|||||||
import { WarnDialogComponent } from 'src/app/modules/warn-dialog/warn-dialog.component';
|
import { WarnDialogComponent } from 'src/app/modules/warn-dialog/warn-dialog.component';
|
||||||
import { Human, UserState } from 'src/app/proto/generated/zitadel/user_pb';
|
import { Human, UserState } from 'src/app/proto/generated/zitadel/user_pb';
|
||||||
|
|
||||||
|
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
||||||
import { CodeDialogComponent } from '../auth-user-detail/code-dialog/code-dialog.component';
|
import { CodeDialogComponent } from '../auth-user-detail/code-dialog/code-dialog.component';
|
||||||
import { EditDialogType } from '../auth-user-detail/edit-dialog/edit-dialog.component';
|
import { EditDialogType } from '../auth-user-detail/edit-dialog/edit-dialog.component';
|
||||||
|
|
||||||
@ -25,15 +26,19 @@ export class ContactComponent {
|
|||||||
public UserState: any = UserState;
|
public UserState: any = UserState;
|
||||||
|
|
||||||
public EditDialogType: any = EditDialogType;
|
public EditDialogType: any = EditDialogType;
|
||||||
constructor(private dialog: MatDialog) {}
|
constructor(private dialog: MatDialog, private authService: GrpcAuthService) {}
|
||||||
|
|
||||||
|
async emitDeletePhone(): Promise<void> {
|
||||||
|
const { resultList } = await this.authService.listMyMultiFactors();
|
||||||
|
const hasSMSOTP = !!resultList.find((mfa) => mfa.otpSms);
|
||||||
|
|
||||||
emitDeletePhone(): void {
|
|
||||||
const dialogRef = this.dialog.open(WarnDialogComponent, {
|
const dialogRef = this.dialog.open(WarnDialogComponent, {
|
||||||
data: {
|
data: {
|
||||||
confirmKey: 'ACTIONS.DELETE',
|
confirmKey: 'ACTIONS.DELETE',
|
||||||
cancelKey: 'ACTIONS.CANCEL',
|
cancelKey: 'ACTIONS.CANCEL',
|
||||||
titleKey: 'USER.LOGINMETHODS.PHONE.DELETETITLE',
|
titleKey: 'USER.LOGINMETHODS.PHONE.DELETETITLE',
|
||||||
descriptionKey: 'USER.LOGINMETHODS.PHONE.DELETEDESC',
|
descriptionKey: 'USER.LOGINMETHODS.PHONE.DELETEDESC',
|
||||||
|
warnSectionKey: hasSMSOTP ? 'USER.LOGINMETHODS.PHONE.OTPSMSREMOVALWARNING' : '',
|
||||||
},
|
},
|
||||||
width: '400px',
|
width: '400px',
|
||||||
});
|
});
|
||||||
|
@ -38,6 +38,7 @@ import { TimestampToDatePipeModule } from 'src/app/pipes/timestamp-to-date-pipe/
|
|||||||
|
|
||||||
import { MatLegacySelectModule as MatSelectModule } from '@angular/material/legacy-select';
|
import { MatLegacySelectModule as MatSelectModule } from '@angular/material/legacy-select';
|
||||||
import { QRCodeModule } from 'angularx-qrcode';
|
import { QRCodeModule } from 'angularx-qrcode';
|
||||||
|
import { InfoDialogModule } from 'src/app/modules/info-dialog/info-dialog.module';
|
||||||
import { MetadataModule } from 'src/app/modules/metadata/metadata.module';
|
import { MetadataModule } from 'src/app/modules/metadata/metadata.module';
|
||||||
import { CountryCallingCodesService } from 'src/app/services/country-calling-codes.service';
|
import { CountryCallingCodesService } from 'src/app/services/country-calling-codes.service';
|
||||||
import { InfoRowModule } from '../../../modules/info-row/info-row.module';
|
import { InfoRowModule } from '../../../modules/info-row/info-row.module';
|
||||||
@ -86,6 +87,7 @@ import { UserMfaComponent } from './user-detail/user-mfa/user-mfa.component';
|
|||||||
ChangesModule,
|
ChangesModule,
|
||||||
CommonModule,
|
CommonModule,
|
||||||
SidenavModule,
|
SidenavModule,
|
||||||
|
InfoDialogModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
MembershipsTableModule,
|
MembershipsTableModule,
|
||||||
|
@ -18,8 +18,10 @@
|
|||||||
<ng-container matColumnDef="type">
|
<ng-container matColumnDef="type">
|
||||||
<th mat-header-cell *matHeaderCellDef>{{ 'USER.MFA.TABLETYPE' | translate }}</th>
|
<th mat-header-cell *matHeaderCellDef>{{ 'USER.MFA.TABLETYPE' | translate }}</th>
|
||||||
<td mat-cell *matCellDef="let mfa">
|
<td mat-cell *matCellDef="let mfa">
|
||||||
<span *ngIf="mfa.otp !== undefined">OTP (One-Time Password)</span>
|
<span *ngIf="mfa.otp !== undefined">TOTP (Time-based One-Time Password)</span>
|
||||||
<span *ngIf="mfa.u2f !== undefined">U2F (Universal 2nd Factor)</span>
|
<span *ngIf="mfa.u2f !== undefined">U2F (Universal 2nd Factor)</span>
|
||||||
|
<span *ngIf="mfa.otpSms !== undefined">One-Time Password SMS</span>
|
||||||
|
<span *ngIf="mfa.otpEmail !== undefined">One-Time Password Email</span>
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
|
@ -16,8 +16,12 @@ import {
|
|||||||
} from 'rxjs/operators';
|
} from 'rxjs/operators';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
AddMyAuthFactorOTPEmailRequest,
|
||||||
|
AddMyAuthFactorOTPEmailResponse,
|
||||||
AddMyAuthFactorOTPRequest,
|
AddMyAuthFactorOTPRequest,
|
||||||
AddMyAuthFactorOTPResponse,
|
AddMyAuthFactorOTPResponse,
|
||||||
|
AddMyAuthFactorOTPSMSRequest,
|
||||||
|
AddMyAuthFactorOTPSMSResponse,
|
||||||
AddMyAuthFactorU2FRequest,
|
AddMyAuthFactorU2FRequest,
|
||||||
AddMyAuthFactorU2FResponse,
|
AddMyAuthFactorU2FResponse,
|
||||||
AddMyPasswordlessLinkRequest,
|
AddMyPasswordlessLinkRequest,
|
||||||
@ -61,8 +65,12 @@ import {
|
|||||||
ListMyUserSessionsResponse,
|
ListMyUserSessionsResponse,
|
||||||
ListMyZitadelPermissionsRequest,
|
ListMyZitadelPermissionsRequest,
|
||||||
ListMyZitadelPermissionsResponse,
|
ListMyZitadelPermissionsResponse,
|
||||||
|
RemoveMyAuthFactorOTPEmailRequest,
|
||||||
|
RemoveMyAuthFactorOTPEmailResponse,
|
||||||
RemoveMyAuthFactorOTPRequest,
|
RemoveMyAuthFactorOTPRequest,
|
||||||
RemoveMyAuthFactorOTPResponse,
|
RemoveMyAuthFactorOTPResponse,
|
||||||
|
RemoveMyAuthFactorOTPSMSRequest,
|
||||||
|
RemoveMyAuthFactorOTPSMSResponse,
|
||||||
RemoveMyAuthFactorU2FRequest,
|
RemoveMyAuthFactorU2FRequest,
|
||||||
RemoveMyAuthFactorU2FResponse,
|
RemoveMyAuthFactorU2FResponse,
|
||||||
RemoveMyAvatarRequest,
|
RemoveMyAvatarRequest,
|
||||||
@ -557,6 +565,18 @@ export class GrpcAuthService {
|
|||||||
return this.grpcService.auth.addMyAuthFactorOTP(new AddMyAuthFactorOTPRequest(), null).then((resp) => resp.toObject());
|
return this.grpcService.auth.addMyAuthFactorOTP(new AddMyAuthFactorOTPRequest(), null).then((resp) => resp.toObject());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public addMyAuthFactorOTPSMS(): Promise<AddMyAuthFactorOTPSMSResponse.AsObject> {
|
||||||
|
return this.grpcService.auth
|
||||||
|
.addMyAuthFactorOTPSMS(new AddMyAuthFactorOTPSMSRequest(), null)
|
||||||
|
.then((resp) => resp.toObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
public addMyAuthFactorOTPEmail(): Promise<AddMyAuthFactorOTPEmailResponse.AsObject> {
|
||||||
|
return this.grpcService.auth
|
||||||
|
.addMyAuthFactorOTPEmail(new AddMyAuthFactorOTPEmailRequest(), null)
|
||||||
|
.then((resp) => resp.toObject());
|
||||||
|
}
|
||||||
|
|
||||||
public addMyMultiFactorU2F(): Promise<AddMyAuthFactorU2FResponse.AsObject> {
|
public addMyMultiFactorU2F(): Promise<AddMyAuthFactorU2FResponse.AsObject> {
|
||||||
return this.grpcService.auth.addMyAuthFactorU2F(new AddMyAuthFactorU2FRequest(), null).then((resp) => resp.toObject());
|
return this.grpcService.auth.addMyAuthFactorU2F(new AddMyAuthFactorU2FRequest(), null).then((resp) => resp.toObject());
|
||||||
}
|
}
|
||||||
@ -617,6 +637,18 @@ export class GrpcAuthService {
|
|||||||
.then((resp) => resp.toObject());
|
.then((resp) => resp.toObject());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public removeMyAuthFactorOTPSMS(): Promise<RemoveMyAuthFactorOTPSMSResponse.AsObject> {
|
||||||
|
return this.grpcService.auth
|
||||||
|
.removeMyAuthFactorOTPSMS(new RemoveMyAuthFactorOTPSMSRequest(), null)
|
||||||
|
.then((resp) => resp.toObject());
|
||||||
|
}
|
||||||
|
|
||||||
|
public removeMyAuthFactorOTPEmail(): Promise<RemoveMyAuthFactorOTPEmailResponse.AsObject> {
|
||||||
|
return this.grpcService.auth
|
||||||
|
.removeMyAuthFactorOTPEmail(new RemoveMyAuthFactorOTPEmailRequest(), null)
|
||||||
|
.then((resp) => resp.toObject());
|
||||||
|
}
|
||||||
|
|
||||||
public verifyMyMultiFactorOTP(code: string): Promise<VerifyMyAuthFactorOTPResponse.AsObject> {
|
public verifyMyMultiFactorOTP(code: string): Promise<VerifyMyAuthFactorOTPResponse.AsObject> {
|
||||||
const req = new VerifyMyAuthFactorOTPRequest();
|
const req = new VerifyMyAuthFactorOTPRequest();
|
||||||
req.setCode(code);
|
req.setCode(code);
|
||||||
|
@ -414,6 +414,12 @@
|
|||||||
"U2F_SUCCESS": "Факторът е добавен успешно!",
|
"U2F_SUCCESS": "Факторът е добавен успешно!",
|
||||||
"U2F_ERROR": "Възникна грешка по време на настройката!",
|
"U2F_ERROR": "Възникна грешка по време на настройката!",
|
||||||
"U2F_NAME": "Име на автентификатора",
|
"U2F_NAME": "Име на автентификатора",
|
||||||
|
"OTPSMS": "OTP (One-Time password) c SMS",
|
||||||
|
"OTPEMAIL": "OTP (еднократна парола) с имейл",
|
||||||
|
"SETUPOTPSMSDESCRIPTION": "Искате ли да настроите този телефонен номер като OTP (еднократна парола) втори фактор?",
|
||||||
|
"OTPSMSSUCCESS": "OTP Factor е настроен успешно.",
|
||||||
|
"OTPSMSPHONEMUSTBEVERIFIED": "Вашият телефон трябва да бъде потвърден, за да използвате този метод.",
|
||||||
|
"OTPEMAILSUCCESS": "OTP Factor е настроен успешно.",
|
||||||
"TYPE": {
|
"TYPE": {
|
||||||
"0": "Няма дефинирани MFA",
|
"0": "Няма дефинирани MFA",
|
||||||
"1": "Еднократна парола (OTP)",
|
"1": "Еднократна парола (OTP)",
|
||||||
@ -580,7 +586,8 @@
|
|||||||
"EDITVALUE": "Телефонен номер",
|
"EDITVALUE": "Телефонен номер",
|
||||||
"EDITDESC": "Въведете новия телефонен номер в полето по-долу.",
|
"EDITDESC": "Въведете новия телефонен номер в полето по-долу.",
|
||||||
"DELETETITLE": "Изтриване на телефонен номер",
|
"DELETETITLE": "Изтриване на телефонен номер",
|
||||||
"DELETEDESC": "Наистина ли искате да изтриете телефонния номер"
|
"DELETEDESC": "Наистина ли искате да изтриете телефонния номер",
|
||||||
|
"OTPSMSREMOVALWARNING": "Този акаунт използва този телефонен номер като втори фактор. Няма да можете да го използвате, след като продължите."
|
||||||
},
|
},
|
||||||
"RESENDCODE": "Код за препращане",
|
"RESENDCODE": "Код за препращане",
|
||||||
"ENTERCODE": "Проверете",
|
"ENTERCODE": "Проверете",
|
||||||
|
@ -411,7 +411,7 @@
|
|||||||
"DESCRIPTION": "Füge einen zusätzlichen Faktor hinzu, um Dein Konto optimal zu schützen.",
|
"DESCRIPTION": "Füge einen zusätzlichen Faktor hinzu, um Dein Konto optimal zu schützen.",
|
||||||
"MANAGE_DESCRIPTION": "Verwalte die Multifaktor-Merkmale Deiner Benutzer.",
|
"MANAGE_DESCRIPTION": "Verwalte die Multifaktor-Merkmale Deiner Benutzer.",
|
||||||
"ADD": "Faktor hinzufügen",
|
"ADD": "Faktor hinzufügen",
|
||||||
"OTP": "Authentikator App für OTP (One-Time Password)",
|
"OTP": "Authentikator App für TOTP (Time-based One-Time Password)",
|
||||||
"OTP_DIALOG_TITLE": "OTP hinzufügen",
|
"OTP_DIALOG_TITLE": "OTP hinzufügen",
|
||||||
"OTP_DIALOG_DESCRIPTION": "Scanne den QR-Code mit einer Authenticator App und verifiziere den erhaltenen Code, um OTP zu aktivieren.",
|
"OTP_DIALOG_DESCRIPTION": "Scanne den QR-Code mit einer Authenticator App und verifiziere den erhaltenen Code, um OTP zu aktivieren.",
|
||||||
"U2F": "Fingerabdruck, Security Key, Face ID oder andere",
|
"U2F": "Fingerabdruck, Security Key, Face ID oder andere",
|
||||||
@ -420,6 +420,12 @@
|
|||||||
"U2F_SUCCESS": "Faktor erfolgreich hinzugefügt!",
|
"U2F_SUCCESS": "Faktor erfolgreich hinzugefügt!",
|
||||||
"U2F_ERROR": "Ein Fehler ist aufgetreten!",
|
"U2F_ERROR": "Ein Fehler ist aufgetreten!",
|
||||||
"U2F_NAME": "Authenticator Name",
|
"U2F_NAME": "Authenticator Name",
|
||||||
|
"OTPSMS": "OTP (One-Time Password) mit SMS",
|
||||||
|
"OTPEMAIL": "OTP (One-Time Password) mit E-Mail",
|
||||||
|
"SETUPOTPSMSDESCRIPTION": "Möchten Sie diese Telefonnummer als zweiten OTP-Faktor (Einmalpasswort) einrichten?",
|
||||||
|
"OTPSMSSUCCESS": "OTP Faktor erfolgrech hinzugefügt.",
|
||||||
|
"OTPSMSPHONEMUSTBEVERIFIED": "Um diese Methode nutzen zu können, muss Ihr Telefon verifiziert werden.",
|
||||||
|
"OTPEMAILSUCCESS": "OTP Faktor erfolgrech hinzugefügt.",
|
||||||
"TYPE": {
|
"TYPE": {
|
||||||
"0": "Keine MFA definiert",
|
"0": "Keine MFA definiert",
|
||||||
"1": "OTP",
|
"1": "OTP",
|
||||||
@ -586,7 +592,8 @@
|
|||||||
"EDITVALUE": "Telefonnummer",
|
"EDITVALUE": "Telefonnummer",
|
||||||
"EDITDESC": "Geben Sie die neue Nummer in dem darunterliegenden Feld ein!",
|
"EDITDESC": "Geben Sie die neue Nummer in dem darunterliegenden Feld ein!",
|
||||||
"DELETETITLE": "Telefonnummer löschen",
|
"DELETETITLE": "Telefonnummer löschen",
|
||||||
"DELETEDESC": "Wollen Sie die Telefonnummer wirklich löschen?"
|
"DELETEDESC": "Wollen Sie die Telefonnummer wirklich löschen?",
|
||||||
|
"OTPSMSREMOVALWARNING": "Dieses Konto verwendet diese Telefonnummer als zweiten Faktor. Wenn Sie fortfahren können Sie nicht mehr darauf zugreifen."
|
||||||
},
|
},
|
||||||
"RESENDCODE": "Code erneut senden",
|
"RESENDCODE": "Code erneut senden",
|
||||||
"ENTERCODE": "Verifizieren",
|
"ENTERCODE": "Verifizieren",
|
||||||
|
@ -412,7 +412,7 @@
|
|||||||
"DESCRIPTION": "Add a second factor to ensure optimal security for your account.",
|
"DESCRIPTION": "Add a second factor to ensure optimal security for your account.",
|
||||||
"MANAGE_DESCRIPTION": "Manage the second factor methods of your users.",
|
"MANAGE_DESCRIPTION": "Manage the second factor methods of your users.",
|
||||||
"ADD": "Add Factor",
|
"ADD": "Add Factor",
|
||||||
"OTP": "Authenticator App for OTP (One-Time Password)",
|
"OTP": "Authenticator App for TOTP (Time-based One-Time Password)",
|
||||||
"OTP_DIALOG_TITLE": "Add OTP",
|
"OTP_DIALOG_TITLE": "Add OTP",
|
||||||
"OTP_DIALOG_DESCRIPTION": "Scan the QR code with an authenticator app and enter the code below to verify and activate the OTP method.",
|
"OTP_DIALOG_DESCRIPTION": "Scan the QR code with an authenticator app and enter the code below to verify and activate the OTP method.",
|
||||||
"U2F": "Fingerprint, Security Keys, Face ID and other",
|
"U2F": "Fingerprint, Security Keys, Face ID and other",
|
||||||
@ -421,6 +421,12 @@
|
|||||||
"U2F_SUCCESS": "Factor added successfully!",
|
"U2F_SUCCESS": "Factor added successfully!",
|
||||||
"U2F_ERROR": "An error during setup occurred!",
|
"U2F_ERROR": "An error during setup occurred!",
|
||||||
"U2F_NAME": "Authenticator Name",
|
"U2F_NAME": "Authenticator Name",
|
||||||
|
"OTPSMS": "OTP (One-Time Password) with SMS",
|
||||||
|
"OTPEMAIL": "OTP (One-Time Password) with Email",
|
||||||
|
"SETUPOTPSMSDESCRIPTION": "Do you want to setup this phonenumber as OTP (One-Time password) second factor?",
|
||||||
|
"OTPSMSSUCCESS": "OTP factor set up with success.",
|
||||||
|
"OTPSMSPHONEMUSTBEVERIFIED": "Your phone must be verified in order to use this method.",
|
||||||
|
"OTPEMAILSUCCESS": "OTP factor set up with success.",
|
||||||
"TYPE": {
|
"TYPE": {
|
||||||
"0": "No MFA defined",
|
"0": "No MFA defined",
|
||||||
"1": "One Time Password (OTP)",
|
"1": "One Time Password (OTP)",
|
||||||
@ -587,7 +593,8 @@
|
|||||||
"EDITVALUE": "Phone number",
|
"EDITVALUE": "Phone number",
|
||||||
"EDITDESC": "Enter the new phone number in the field below.",
|
"EDITDESC": "Enter the new phone number in the field below.",
|
||||||
"DELETETITLE": "Delete phone number",
|
"DELETETITLE": "Delete phone number",
|
||||||
"DELETEDESC": "Do you really want to delete the phone number"
|
"DELETEDESC": "Do you really want to delete the phone number",
|
||||||
|
"OTPSMSREMOVALWARNING": "This account uses this phone number as second factor. You won't be able to use it after you proceed."
|
||||||
},
|
},
|
||||||
"RESENDCODE": "Resend Code",
|
"RESENDCODE": "Resend Code",
|
||||||
"ENTERCODE": "Verify",
|
"ENTERCODE": "Verify",
|
||||||
|
@ -412,8 +412,8 @@
|
|||||||
"DESCRIPTION": "Añade un doble factor para configurar una seguridad óptima de tu cuenta.",
|
"DESCRIPTION": "Añade un doble factor para configurar una seguridad óptima de tu cuenta.",
|
||||||
"MANAGE_DESCRIPTION": "Gestiona el método de doble factor para tus usuarios.",
|
"MANAGE_DESCRIPTION": "Gestiona el método de doble factor para tus usuarios.",
|
||||||
"ADD": "Añadir factor",
|
"ADD": "Añadir factor",
|
||||||
"OTP": "App autenticadora para OTP (One-Time Password)",
|
"OTP": "App autenticadora para TOTP (Time-based One-Time Password)",
|
||||||
"OTP_DIALOG_TITLE": "Añadir OTP",
|
"OTP_DIALOG_TITLE": "Añadir TOTP",
|
||||||
"OTP_DIALOG_DESCRIPTION": "Escanea el código QR con una app autenticadora introduciendo el siguiente código para verificar y activar el método OTP.",
|
"OTP_DIALOG_DESCRIPTION": "Escanea el código QR con una app autenticadora introduciendo el siguiente código para verificar y activar el método OTP.",
|
||||||
"U2F": "Huella dactilar, claves de seguridad, Face ID y otros",
|
"U2F": "Huella dactilar, claves de seguridad, Face ID y otros",
|
||||||
"U2F_DIALOG_TITLE": "Verificar factor",
|
"U2F_DIALOG_TITLE": "Verificar factor",
|
||||||
@ -421,6 +421,12 @@
|
|||||||
"U2F_SUCCESS": "¡Factor añadido con éxito!",
|
"U2F_SUCCESS": "¡Factor añadido con éxito!",
|
||||||
"U2F_ERROR": "¡Se produjo un error durante la configuración!",
|
"U2F_ERROR": "¡Se produjo un error durante la configuración!",
|
||||||
"U2F_NAME": "Nombre del autenticador",
|
"U2F_NAME": "Nombre del autenticador",
|
||||||
|
"OTPSMS": "OTP (One-Time Password) con SMS",
|
||||||
|
"OTPEMAIL": "OTP (contraseña de un solo uso) con correo electrónico",
|
||||||
|
"SETUPOTPSMSDESCRIPTION": "¿Desea configurar este número de teléfono como segundo factor OTP (contraseña de un solo uso)?",
|
||||||
|
"OTPSMSSUCCESS": "Factor OTP establecido con éxito.",
|
||||||
|
"OTPSMSPHONEMUSTBEVERIFIED": "Su teléfono debe estar verificado para usar este método.",
|
||||||
|
"OTPEMAILSUCCESS": "Factor OTP establecido con éxito.",
|
||||||
"TYPE": {
|
"TYPE": {
|
||||||
"0": "No se ha definido MFA",
|
"0": "No se ha definido MFA",
|
||||||
"1": "One Time Password (OTP)",
|
"1": "One Time Password (OTP)",
|
||||||
@ -587,7 +593,8 @@
|
|||||||
"EDITVALUE": "Número de teléfono",
|
"EDITVALUE": "Número de teléfono",
|
||||||
"EDITDESC": "Introduce el número de teléfono en el siguiente campo.",
|
"EDITDESC": "Introduce el número de teléfono en el siguiente campo.",
|
||||||
"DELETETITLE": "Borrar número de teléfono",
|
"DELETETITLE": "Borrar número de teléfono",
|
||||||
"DELETEDESC": "Estás seguro que quieres borrar el número de teléfono"
|
"DELETEDESC": "Estás seguro que quieres borrar el número de teléfono",
|
||||||
|
"OTPSMSREMOVALWARNING": "Esta cuenta utiliza este número de teléfono como segundo factor. No podrá usarlo después de continuar."
|
||||||
},
|
},
|
||||||
"RESENDCODE": "Reenviar el código",
|
"RESENDCODE": "Reenviar el código",
|
||||||
"ENTERCODE": "Verificar",
|
"ENTERCODE": "Verificar",
|
||||||
|
@ -411,8 +411,8 @@
|
|||||||
"DESCRIPTION": "Ajoutez un second facteur pour garantir une sécurité optimale de votre compte.",
|
"DESCRIPTION": "Ajoutez un second facteur pour garantir une sécurité optimale de votre compte.",
|
||||||
"MANAGE_DESCRIPTION": "Gérez les méthodes de second facteur de vos utilisateurs.",
|
"MANAGE_DESCRIPTION": "Gérez les méthodes de second facteur de vos utilisateurs.",
|
||||||
"ADD": "Ajouter un facteur",
|
"ADD": "Ajouter un facteur",
|
||||||
"OTP": "Application d'authentification pour OTP (One-time password)",
|
"OTP": "Application d'authentification pour TOTP (Time-based One-time password)",
|
||||||
"OTP_DIALOG_TITLE": "Ajouter un OTP",
|
"OTP_DIALOG_TITLE": "Ajouter un TOTP",
|
||||||
"OTP_DIALOG_DESCRIPTION": "Scannez le code QR avec une application d'authentification et saisissez le code ci-dessous pour vérifier et activer la méthode OTP.",
|
"OTP_DIALOG_DESCRIPTION": "Scannez le code QR avec une application d'authentification et saisissez le code ci-dessous pour vérifier et activer la méthode OTP.",
|
||||||
"U2F": "Empreinte digitale, clés de sécurité, Face ID et autres",
|
"U2F": "Empreinte digitale, clés de sécurité, Face ID et autres",
|
||||||
"U2F_DIALOG_TITLE": "Vérifier le facteur",
|
"U2F_DIALOG_TITLE": "Vérifier le facteur",
|
||||||
@ -420,6 +420,12 @@
|
|||||||
"U2F_SUCCESS": "Facteur ajouté avec succès !",
|
"U2F_SUCCESS": "Facteur ajouté avec succès !",
|
||||||
"U2F_ERROR": "Une erreur s'est produite pendant l'installation !",
|
"U2F_ERROR": "Une erreur s'est produite pendant l'installation !",
|
||||||
"U2F_NAME": "Nom de l'authentificateur",
|
"U2F_NAME": "Nom de l'authentificateur",
|
||||||
|
"OTPSMS": "OTP (One-Time Password) avec SMS",
|
||||||
|
"OTPEMAIL": "OTP (password monouso) con e-mail",
|
||||||
|
"SETUPOTPSMSDESCRIPTION": "Voulez-vous configurer ce numéro de téléphone comme deuxième facteur OTP (mot de passe à usage unique) ?",
|
||||||
|
"OTPSMSSUCCESS": "OTP Factor mis en place avec succès.",
|
||||||
|
"OTPSMSPHONEMUSTBEVERIFIED": "Votre téléphone doit être vérifié pour pouvoir utiliser cette méthode.",
|
||||||
|
"OTPEMAILSUCCESS": "OTP Factor mis en place avec succès.",
|
||||||
"TYPE": {
|
"TYPE": {
|
||||||
"0": "Pas de MFA défini",
|
"0": "Pas de MFA défini",
|
||||||
"1": "Mot de passe à usage unique (OTP)",
|
"1": "Mot de passe à usage unique (OTP)",
|
||||||
@ -586,7 +592,8 @@
|
|||||||
"EDITVALUE": "Numéro de téléphone",
|
"EDITVALUE": "Numéro de téléphone",
|
||||||
"EDITDESC": "Entrez le nouveau numéro de téléphone dans le champ ci-dessous.",
|
"EDITDESC": "Entrez le nouveau numéro de téléphone dans le champ ci-dessous.",
|
||||||
"DELETETITLE": "Supprimer le numéro de téléphone",
|
"DELETETITLE": "Supprimer le numéro de téléphone",
|
||||||
"DELETEDESC": "Voulez-vous vraiment supprimer le numéro de téléphone ?"
|
"DELETEDESC": "Voulez-vous vraiment supprimer le numéro de téléphone ?",
|
||||||
|
"OTPSMSREMOVALWARNING": "Ce compte utilise ce numéro de téléphone comme deuxième facteur. Vous ne pourrez plus l'utiliser après avoir continué."
|
||||||
},
|
},
|
||||||
"RESENDCODE": "Renvoyer le code",
|
"RESENDCODE": "Renvoyer le code",
|
||||||
"ENTERCODE": "Vérifier",
|
"ENTERCODE": "Vérifier",
|
||||||
|
@ -410,8 +410,8 @@
|
|||||||
"DESCRIPTION": "Aggiungi un secondo fattore per garantire la sicurezza ottimale del tuo account.",
|
"DESCRIPTION": "Aggiungi un secondo fattore per garantire la sicurezza ottimale del tuo account.",
|
||||||
"MANAGE_DESCRIPTION": "Gestite i metodi del secondo fattore dei vostri utenti.",
|
"MANAGE_DESCRIPTION": "Gestite i metodi del secondo fattore dei vostri utenti.",
|
||||||
"ADD": "Aggiungi fattore",
|
"ADD": "Aggiungi fattore",
|
||||||
"OTP": "App di autenticazione per OTP (One-Time Password)",
|
"OTP": "App di autenticazione per TOTP (Time-based One-Time Password)",
|
||||||
"OTP_DIALOG_TITLE": "Aggiungi OTP",
|
"OTP_DIALOG_TITLE": "Aggiungi TOTP",
|
||||||
"OTP_DIALOG_DESCRIPTION": "Scansiona il codice QR con un'app di autenticazione e inserisci il codice nel campo sottostante per verificare e attivare il metodo OTP.",
|
"OTP_DIALOG_DESCRIPTION": "Scansiona il codice QR con un'app di autenticazione e inserisci il codice nel campo sottostante per verificare e attivare il metodo OTP.",
|
||||||
"U2F": "Impronta digitale, chiave di sicurezza, Face ID e altri",
|
"U2F": "Impronta digitale, chiave di sicurezza, Face ID e altri",
|
||||||
"U2F_DIALOG_TITLE": "Verifica Fattore",
|
"U2F_DIALOG_TITLE": "Verifica Fattore",
|
||||||
@ -419,6 +419,12 @@
|
|||||||
"U2F_SUCCESS": "Fattore aggiunto con successo!",
|
"U2F_SUCCESS": "Fattore aggiunto con successo!",
|
||||||
"U2F_ERROR": "Si \u00e8 verificato un errore durante la configurazione!",
|
"U2F_ERROR": "Si \u00e8 verificato un errore durante la configurazione!",
|
||||||
"U2F_NAME": "Nome dell'autenticatore",
|
"U2F_NAME": "Nome dell'autenticatore",
|
||||||
|
"OTPSMS": "OTP (One-Time Password) con SMS",
|
||||||
|
"OTPEMAIL": "OTP (One-Time Password) with Email",
|
||||||
|
"SETUPOTPSMSDESCRIPTION": "Vuoi impostare questo numero di telefono come secondo fattore OTP (One-Time password)?",
|
||||||
|
"OTPSMSSUCCESS": "Fattore OTP impostato con successo.",
|
||||||
|
"OTPSMSPHONEMUSTBEVERIFIED": "Il tuo telefono deve essere verificato per utilizzare questo metodo.",
|
||||||
|
"OTPEMAILSUCCESS": "Fattore OTP impostato con successo.",
|
||||||
"TYPE": {
|
"TYPE": {
|
||||||
"0": "Nessun altro fattore definito",
|
"0": "Nessun altro fattore definito",
|
||||||
"1": "One Time Password (OTP)",
|
"1": "One Time Password (OTP)",
|
||||||
@ -585,7 +591,8 @@
|
|||||||
"EDITVALUE": "Numero di telefono",
|
"EDITVALUE": "Numero di telefono",
|
||||||
"EDITDESC": "Inserisci il nuovo numero di telefono nel campo sottostante.",
|
"EDITDESC": "Inserisci il nuovo numero di telefono nel campo sottostante.",
|
||||||
"DELETETITLE": "Rimuovi il numero di telefono",
|
"DELETETITLE": "Rimuovi il numero di telefono",
|
||||||
"DELETEDESC": "Vuoi davvero rimuovere il numero di telefono"
|
"DELETEDESC": "Vuoi davvero rimuovere il numero di telefono",
|
||||||
|
"OTPSMSREMOVALWARNING": "Questo account utilizza questo numero di telefono come secondo fattore. Non sarai in grado di usarlo dopo aver proceduto."
|
||||||
},
|
},
|
||||||
"RESENDCODE": "Reinvia il codice",
|
"RESENDCODE": "Reinvia il codice",
|
||||||
"ENTERCODE": "Verifica",
|
"ENTERCODE": "Verifica",
|
||||||
|
@ -412,7 +412,7 @@
|
|||||||
"DESCRIPTION": "二要素認証を追加して、アカウントに最適なセキュリティを確保します。",
|
"DESCRIPTION": "二要素認証を追加して、アカウントに最適なセキュリティを確保します。",
|
||||||
"MANAGE_DESCRIPTION": "ユーザーの二要素認証を管理する。",
|
"MANAGE_DESCRIPTION": "ユーザーの二要素認証を管理する。",
|
||||||
"ADD": "二要素認証を追加する",
|
"ADD": "二要素認証を追加する",
|
||||||
"OTP": "OTP用認証アプリ(ワンタイム・パスワード)",
|
"OTP": "TOTP用認証アプリ(ワンタイム・パスワード)",
|
||||||
"OTP_DIALOG_TITLE": "OTPの追加",
|
"OTP_DIALOG_TITLE": "OTPの追加",
|
||||||
"OTP_DIALOG_DESCRIPTION": "認証アプリでQRコードを読み取り、下記のコードを入力することで、OTP方式の確認と有効化ができます。",
|
"OTP_DIALOG_DESCRIPTION": "認証アプリでQRコードを読み取り、下記のコードを入力することで、OTP方式の確認と有効化ができます。",
|
||||||
"U2F": "指紋、セキュリティキー、フェイスIDなど",
|
"U2F": "指紋、セキュリティキー、フェイスIDなど",
|
||||||
@ -421,6 +421,12 @@
|
|||||||
"U2F_SUCCESS": "二要素認証が正常に追加されました!",
|
"U2F_SUCCESS": "二要素認証が正常に追加されました!",
|
||||||
"U2F_ERROR": "セットアップ中にエラーが発生しました!",
|
"U2F_ERROR": "セットアップ中にエラーが発生しました!",
|
||||||
"U2F_NAME": "認証者名",
|
"U2F_NAME": "認証者名",
|
||||||
|
"OTPSMS": "OTP(ワンタイムパスワード)とSMS",
|
||||||
|
"OTPEMAIL": "電子メールによる OTP (ワンタイム パスワード)",
|
||||||
|
"SETUPOTPSMSDESCRIPTION": "この電話番号を OTP (ワンタイム パスワード) の第 2 要素として設定しますか?",
|
||||||
|
"OTPSMSSUCCESS": "OTP 係数の設定が成功しました。",
|
||||||
|
"OTPSMSPHONEMUSTBEVERIFIED": "この方法を使用するには、電話を認証する必要があります。",
|
||||||
|
"OTPEMAILSUCCESS": "OTP 係数の設定が成功しました。",
|
||||||
"TYPE": {
|
"TYPE": {
|
||||||
"0": "MFAは定義されていません",
|
"0": "MFAは定義されていません",
|
||||||
"1": "ワンタイムパスワード(OTP)",
|
"1": "ワンタイムパスワード(OTP)",
|
||||||
@ -587,7 +593,8 @@
|
|||||||
"EDITVALUE": "電話番号",
|
"EDITVALUE": "電話番号",
|
||||||
"EDITDESC": "下のフィールドに新しい電話番号を入力してください。",
|
"EDITDESC": "下のフィールドに新しい電話番号を入力してください。",
|
||||||
"DELETETITLE": "電話番号の削除",
|
"DELETETITLE": "電話番号の削除",
|
||||||
"DELETEDESC": "本当に電話番号を削除してよろしいですか?"
|
"DELETEDESC": "本当に電話番号を削除してよろしいですか?",
|
||||||
|
"OTPSMSREMOVALWARNING": "このアカウントは、この電話番号を 2 番目の要素として使用します。続行すると使用できなくなります。"
|
||||||
},
|
},
|
||||||
"RESENDCODE": "再送信コード",
|
"RESENDCODE": "再送信コード",
|
||||||
"ENTERCODE": "認証",
|
"ENTERCODE": "認証",
|
||||||
|
@ -412,7 +412,7 @@
|
|||||||
"DESCRIPTION": "Додадете втор фактор за оптимална безбедност на вашиот профил.",
|
"DESCRIPTION": "Додадете втор фактор за оптимална безбедност на вашиот профил.",
|
||||||
"MANAGE_DESCRIPTION": "Управувајте со методите за втор фактор за вашите корисници.",
|
"MANAGE_DESCRIPTION": "Управувајте со методите за втор фактор за вашите корисници.",
|
||||||
"ADD": "Додади фактор",
|
"ADD": "Додади фактор",
|
||||||
"OTP": "Апликација за автентикација со OTP (Еднократна Лозинка)",
|
"OTP": "Апликација за автентикација со TOTP (Еднократна Лозинка)",
|
||||||
"OTP_DIALOG_TITLE": "Додади OTP",
|
"OTP_DIALOG_TITLE": "Додади OTP",
|
||||||
"OTP_DIALOG_DESCRIPTION": "Скенирајте го QR-кодот со автентикатор апликација и внесете го кодот подолу за да го верификувате и активирате методот OTP.",
|
"OTP_DIALOG_DESCRIPTION": "Скенирајте го QR-кодот со автентикатор апликација и внесете го кодот подолу за да го верификувате и активирате методот OTP.",
|
||||||
"U2F": "Отпечаток на прст, безбедносни клучеви, Face ID и други",
|
"U2F": "Отпечаток на прст, безбедносни клучеви, Face ID и други",
|
||||||
@ -421,6 +421,12 @@
|
|||||||
"U2F_SUCCESS": "Факторот е успешно додаден!",
|
"U2F_SUCCESS": "Факторот е успешно додаден!",
|
||||||
"U2F_ERROR": "Се појави грешка при подесувањето!",
|
"U2F_ERROR": "Се појави грешка при подесувањето!",
|
||||||
"U2F_NAME": "Име на автентикатор",
|
"U2F_NAME": "Име на автентикатор",
|
||||||
|
"OTPSMS": "ОТП (еднократна лозинка) со СМС",
|
||||||
|
"OTPEMAIL": "OTP (еднократна лозинка) со е-пошта",
|
||||||
|
"SETUPOTPSMSDESCRIPTION": "Дали сакате да го поставите овој телефонски број како втор фактор OTP (еднократна лозинка)?",
|
||||||
|
"OTPSMSSUCCESS": "OTP Factor е поставен со успех.",
|
||||||
|
"OTPSMSPHONEMUSTBEVERIFIED": "Вашиот телефон мора да биде потврден за да го користите овој метод.",
|
||||||
|
"OTPEMAILSUCCESS": "OTP Factor е поставен со успех.",
|
||||||
"TYPE": {
|
"TYPE": {
|
||||||
"0": "Нема дефинирана MFA",
|
"0": "Нема дефинирана MFA",
|
||||||
"1": "Еднократна лозинка (OTP)",
|
"1": "Еднократна лозинка (OTP)",
|
||||||
@ -587,7 +593,8 @@
|
|||||||
"EDITVALUE": "Телефонски број",
|
"EDITVALUE": "Телефонски број",
|
||||||
"EDITDESC": "Внесете го новиот телефонски број во полето подолу.",
|
"EDITDESC": "Внесете го новиот телефонски број во полето подолу.",
|
||||||
"DELETETITLE": "Избриши телефонски број",
|
"DELETETITLE": "Избриши телефонски број",
|
||||||
"DELETEDESC": "Дали навистина сакате да го избришете телефонскиот број"
|
"DELETEDESC": "Дали навистина сакате да го избришете телефонскиот број",
|
||||||
|
"OTPSMSREMOVALWARNING": "Оваа сметка го користи овој телефонски број како втор фактор. Нема да можете да го користите откако ќе продолжите."
|
||||||
},
|
},
|
||||||
"RESENDCODE": "Повторно испрати код",
|
"RESENDCODE": "Повторно испрати код",
|
||||||
"ENTERCODE": "Верифицирај",
|
"ENTERCODE": "Верифицирај",
|
||||||
|
@ -411,8 +411,8 @@
|
|||||||
"DESCRIPTION": "Dodaj drugi czynnik, aby zapewnić optymalne bezpieczeństwo twojego konta.",
|
"DESCRIPTION": "Dodaj drugi czynnik, aby zapewnić optymalne bezpieczeństwo twojego konta.",
|
||||||
"MANAGE_DESCRIPTION": "Zarządzaj metodami drugiego czynnika swoich użytkowników.",
|
"MANAGE_DESCRIPTION": "Zarządzaj metodami drugiego czynnika swoich użytkowników.",
|
||||||
"ADD": "Dodaj czynnik",
|
"ADD": "Dodaj czynnik",
|
||||||
"OTP": "Aplikacja uwierzytelniająca OTP (jednorazowe hasło)",
|
"OTP": "Aplikacja uwierzytelniająca TOTP (jednorazowe hasło)",
|
||||||
"OTP_DIALOG_TITLE": "Dodaj OTP",
|
"OTP_DIALOG_TITLE": "Dodaj TOTP",
|
||||||
"OTP_DIALOG_DESCRIPTION": "Zeskanuj kod QR za pomocą aplikacji uwierzytelniającej i wprowadź poniższy kod, aby zweryfikować i aktywować metodę OTP.",
|
"OTP_DIALOG_DESCRIPTION": "Zeskanuj kod QR za pomocą aplikacji uwierzytelniającej i wprowadź poniższy kod, aby zweryfikować i aktywować metodę OTP.",
|
||||||
"U2F": "Odcisk palca, klucze bezpieczeństwa, Face ID i inne",
|
"U2F": "Odcisk palca, klucze bezpieczeństwa, Face ID i inne",
|
||||||
"U2F_DIALOG_TITLE": "Zweryfikuj czynnik",
|
"U2F_DIALOG_TITLE": "Zweryfikuj czynnik",
|
||||||
@ -420,6 +420,12 @@
|
|||||||
"U2F_SUCCESS": "Czynnik został pomyślnie dodany!",
|
"U2F_SUCCESS": "Czynnik został pomyślnie dodany!",
|
||||||
"U2F_ERROR": "Wystąpił błąd podczas konfiguracji!",
|
"U2F_ERROR": "Wystąpił błąd podczas konfiguracji!",
|
||||||
"U2F_NAME": "Nazwa uwierzytelniacza",
|
"U2F_NAME": "Nazwa uwierzytelniacza",
|
||||||
|
"OTPSMS": "OTP (hasło jednorazowe) z SMS-em",
|
||||||
|
"OTPEMAIL": "OTP (hasło jednorazowe) z e-mailem",
|
||||||
|
"SETUPOTPSMSDESCRIPTION": "Czy chcesz ustawić ten numer telefonu jako drugi czynnik OTP (hasło jednorazowe)?",
|
||||||
|
"OTPSMSSUCCESS": "Pomyślnie skonfigurowano współczynnik OTP.",
|
||||||
|
"OTPSMSPHONEMUSTBEVERIFIED": "Aby skorzystać z tej metody, Twój telefon musi zostać zweryfikowany.",
|
||||||
|
"OTPEMAILSUCCESS": "Pomyślnie skonfigurowano współczynnik OTP.",
|
||||||
"TYPE": {
|
"TYPE": {
|
||||||
"0": "Nie zdefiniowano MFA",
|
"0": "Nie zdefiniowano MFA",
|
||||||
"1": "Jednorazowe hasło (OTP)",
|
"1": "Jednorazowe hasło (OTP)",
|
||||||
@ -586,7 +592,8 @@
|
|||||||
"EDITVALUE": "Numer telefonu",
|
"EDITVALUE": "Numer telefonu",
|
||||||
"EDITDESC": "Wprowadź nowy numer telefonu poniżej.",
|
"EDITDESC": "Wprowadź nowy numer telefonu poniżej.",
|
||||||
"DELETETITLE": "Usuń numer telefonu",
|
"DELETETITLE": "Usuń numer telefonu",
|
||||||
"DELETEDESC": "Czy na pewno chcesz usunąć numer telefonu"
|
"DELETEDESC": "Czy na pewno chcesz usunąć numer telefonu",
|
||||||
|
"OTPSMSREMOVALWARNING": "To konto używa tego numeru telefonu jako drugiego czynnika. Po przejściu dalej nie będziesz mógł z niego korzystać."
|
||||||
},
|
},
|
||||||
"RESENDCODE": "Wyślij kod ponownie",
|
"RESENDCODE": "Wyślij kod ponownie",
|
||||||
"ENTERCODE": "Zweryfikuj",
|
"ENTERCODE": "Zweryfikuj",
|
||||||
|
@ -412,7 +412,7 @@
|
|||||||
"DESCRIPTION": "Adicione um segundo fator para garantir a segurança ideal da sua conta.",
|
"DESCRIPTION": "Adicione um segundo fator para garantir a segurança ideal da sua conta.",
|
||||||
"MANAGE_DESCRIPTION": "Gerencie os métodos de segundo fator dos seus usuários.",
|
"MANAGE_DESCRIPTION": "Gerencie os métodos de segundo fator dos seus usuários.",
|
||||||
"ADD": "Adicionar Fator",
|
"ADD": "Adicionar Fator",
|
||||||
"OTP": "Aplicativo de Autenticação para OTP (One-Time Password)",
|
"OTP": "Aplicativo de Autenticação para TOTP (One-Time Password)",
|
||||||
"OTP_DIALOG_TITLE": "Adicionar OTP",
|
"OTP_DIALOG_TITLE": "Adicionar OTP",
|
||||||
"OTP_DIALOG_DESCRIPTION": "Digitalize o código QR com um aplicativo autenticador e insira o código abaixo para verificar e ativar o método OTP.",
|
"OTP_DIALOG_DESCRIPTION": "Digitalize o código QR com um aplicativo autenticador e insira o código abaixo para verificar e ativar o método OTP.",
|
||||||
"U2F": "Impressão digital, Chaves de Segurança, Face ID e outros",
|
"U2F": "Impressão digital, Chaves de Segurança, Face ID e outros",
|
||||||
@ -421,6 +421,12 @@
|
|||||||
"U2F_SUCCESS": "Fator adicionado com sucesso!",
|
"U2F_SUCCESS": "Fator adicionado com sucesso!",
|
||||||
"U2F_ERROR": "Ocorreu um erro durante a configuração!",
|
"U2F_ERROR": "Ocorreu um erro durante a configuração!",
|
||||||
"U2F_NAME": "Nome do Autenticador",
|
"U2F_NAME": "Nome do Autenticador",
|
||||||
|
"OTPSMS": "OTP (senha de uso único) com SMS",
|
||||||
|
"OTPEMAIL": "OTP (senha de uso único) com e-mail",
|
||||||
|
"SETUPOTPSMSDESCRIPTION": "Deseja configurar este número de telefone como segundo fator OTP (senha de uso único)?",
|
||||||
|
"OTPSMSSUCCESS": "Fator OTP configurado com sucesso.",
|
||||||
|
"OTPSMSPHONEMUSTBEVERIFIED": "Seu telefone deve ser verificado para usar este método.",
|
||||||
|
"OTPEMAILSUCCESS": "Fator OTP configurado com sucesso.",
|
||||||
"TYPE": {
|
"TYPE": {
|
||||||
"0": "Nenhum MFA definido",
|
"0": "Nenhum MFA definido",
|
||||||
"1": "One Time Password (OTP)",
|
"1": "One Time Password (OTP)",
|
||||||
@ -587,7 +593,8 @@
|
|||||||
"EDITVALUE": "Número de Telefone",
|
"EDITVALUE": "Número de Telefone",
|
||||||
"EDITDESC": "Digite o novo número de telefone no campo abaixo.",
|
"EDITDESC": "Digite o novo número de telefone no campo abaixo.",
|
||||||
"DELETETITLE": "Excluir número de telefone",
|
"DELETETITLE": "Excluir número de telefone",
|
||||||
"DELETEDESC": "Você realmente deseja excluir o número de telefone?"
|
"DELETEDESC": "Você realmente deseja excluir o número de telefone?",
|
||||||
|
"OTPSMSREMOVALWARNING": "Esta conta usa este número de telefone como segundo fator. Você não poderá usá-lo depois de continuar."
|
||||||
},
|
},
|
||||||
"RESENDCODE": "Reenviar Código",
|
"RESENDCODE": "Reenviar Código",
|
||||||
"ENTERCODE": "Verificar",
|
"ENTERCODE": "Verificar",
|
||||||
|
@ -411,7 +411,7 @@
|
|||||||
"DESCRIPTION": "添加第二个因素以确保您帐户的最佳安全性。",
|
"DESCRIPTION": "添加第二个因素以确保您帐户的最佳安全性。",
|
||||||
"MANAGE_DESCRIPTION": "管理用户的第二因素身份认证方式。",
|
"MANAGE_DESCRIPTION": "管理用户的第二因素身份认证方式。",
|
||||||
"ADD": "添加因子",
|
"ADD": "添加因子",
|
||||||
"OTP": "用于 OTP 的身份验证器应用程序",
|
"OTP": "用于 TOTP 的身份验证器应用程序",
|
||||||
"OTP_DIALOG_TITLE": "添加 OTP",
|
"OTP_DIALOG_TITLE": "添加 OTP",
|
||||||
"OTP_DIALOG_DESCRIPTION": "使用验证器应用程序扫描二维码并输入下面的代码以验证并激活 OTP 方法。",
|
"OTP_DIALOG_DESCRIPTION": "使用验证器应用程序扫描二维码并输入下面的代码以验证并激活 OTP 方法。",
|
||||||
"U2F": "指纹、安全密钥、Face ID 等",
|
"U2F": "指纹、安全密钥、Face ID 等",
|
||||||
@ -420,6 +420,12 @@
|
|||||||
"U2F_SUCCESS": "身份验证因子添加成功!",
|
"U2F_SUCCESS": "身份验证因子添加成功!",
|
||||||
"U2F_ERROR": "安装过程中发生错误!",
|
"U2F_ERROR": "安装过程中发生错误!",
|
||||||
"U2F_NAME": "身份验证器名称",
|
"U2F_NAME": "身份验证器名称",
|
||||||
|
"OTPSMS": "带短信的 OTP(一次性密码)",
|
||||||
|
"OTPEMAIL": "带电子邮件的 OTP(一次性密码)",
|
||||||
|
"SETUPOTPSMSDESCRIPTION": "您想将此电话号码设置为 OTP(一次性密码)第二因素吗?",
|
||||||
|
"OTPSMSSUCCESS": "OTP 因子设置成功。",
|
||||||
|
"OTPSMSPHONEMUSTBEVERIFIED": "您的手机必须经过验证才能使用此方法。",
|
||||||
|
"OTPEMAILSUCCESS": "OTP 因子设置成功。",
|
||||||
"TYPE": {
|
"TYPE": {
|
||||||
"0": "未定义 MFA",
|
"0": "未定义 MFA",
|
||||||
"1": "一次性密码 (OTP)",
|
"1": "一次性密码 (OTP)",
|
||||||
@ -586,7 +592,8 @@
|
|||||||
"EDITVALUE": "手机号码",
|
"EDITVALUE": "手机号码",
|
||||||
"EDITDESC": "在下面的字段中输入新的手机号码。",
|
"EDITDESC": "在下面的字段中输入新的手机号码。",
|
||||||
"DELETETITLE": "删除手机号码",
|
"DELETETITLE": "删除手机号码",
|
||||||
"DELETEDESC": "你真的要删除手机号码吗"
|
"DELETEDESC": "你真的要删除手机号码吗",
|
||||||
|
"OTPSMSREMOVALWARNING": "此帐户使用此电话号码作为第二因素。继续后您将无法使用它。"
|
||||||
},
|
},
|
||||||
"RESENDCODE": "重新发送验证码",
|
"RESENDCODE": "重新发送验证码",
|
||||||
"ENTERCODE": "验证",
|
"ENTERCODE": "验证",
|
||||||
|
5481
console/yarn.lock
5481
console/yarn.lock
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user