mirror of
https://github.com/zitadel/zitadel.git
synced 2025-08-11 15:37:33 +00:00
fix(FE): allow only enabled factors to be displayed on user page (#9313)
# Which Problems Are Solved
- Hides for users MFA options are not allowed by org policy.
- Fix for "ng test" across "console"
# How the Problems Are Solved
- Before displaying MFA options we call "listMyMultiFactors" from parent
component to filter MFA allowed by org
# Additional Changes
- Dependency Injection was fixed around ng unit tests
# Additional Context
admin view
<img width="698" alt="Screenshot 2025-02-06 at 00 26 50"
src="https://github.com/user-attachments/assets/1b642c8a-a640-4bdd-a1ca-bde70c263567"
/>
user view
<img width="751" alt="Screenshot 2025-02-06 at 00 27 16"
src="https://github.com/user-attachments/assets/e1c99907-3226-46ce-b8bc-e993af4b4cae"
/>
test
<img width="1500" alt="Screenshot 2025-02-06 at 00 01 36"
src="https://github.com/user-attachments/assets/d2d8ead1-9f0f-4916-a2fc-f4db9c71cfa8"
/>
The issue: https://github.com/zitadel/zitadel/issues/9176
The bug report:
https://discord.com/channels/927474939156643850/1307006457815896094
---------
Co-authored-by: a k <rdyto1@macbook-pro-1.home>
Co-authored-by: a k <rdyto1@macbook-pro.home>
Co-authored-by: a k <rdyto1@macbook-pro-2.home>
Co-authored-by: Ramon <mail@conblem.me>
(cherry picked from commit 839c761357
)
This commit is contained in:
@@ -82,6 +82,7 @@
|
||||
"jasmine-spec-reporter": "~7.0.0",
|
||||
"karma": "^6.4.4",
|
||||
"karma-chrome-launcher": "^3.2.0",
|
||||
"karma-coverage": "^2.2.1",
|
||||
"karma-coverage-istanbul-reporter": "^3.0.3",
|
||||
"karma-jasmine": "^5.1.0",
|
||||
"karma-jasmine-html-reporter": "^2.1.0",
|
||||
|
@@ -1,16 +1,16 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { QuickstartComponent } from './quickstart.component';
|
||||
import { OIDCConfigurationComponent } from './oidc-configuration.component';
|
||||
|
||||
describe('QuickstartComponent', () => {
|
||||
let component: QuickstartComponent;
|
||||
let fixture: ComponentFixture<QuickstartComponent>;
|
||||
let component: OIDCConfigurationComponent;
|
||||
let fixture: ComponentFixture<OIDCConfigurationComponent>;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [QuickstartComponent],
|
||||
declarations: [OIDCConfigurationComponent],
|
||||
});
|
||||
fixture = TestBed.createComponent(QuickstartComponent);
|
||||
fixture = TestBed.createComponent(OIDCConfigurationComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
@@ -1,19 +1,19 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { OrgDomainsComponent } from './org-domains.component';
|
||||
import { DomainsComponent } from './domains.component';
|
||||
|
||||
describe('OrgDomainsComponent', () => {
|
||||
let component: OrgDomainsComponent;
|
||||
let fixture: ComponentFixture<OrgDomainsComponent>;
|
||||
let component: DomainsComponent;
|
||||
let fixture: ComponentFixture<DomainsComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [OrgDomainsComponent],
|
||||
declarations: [DomainsComponent],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(OrgDomainsComponent);
|
||||
fixture = TestBed.createComponent(DomainsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
@@ -1,19 +1,19 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { FilterUserComponent } from './filter-user.component';
|
||||
import { FilterProjectComponent } from './filter-project.component';
|
||||
|
||||
describe('FilterUserComponent', () => {
|
||||
let component: FilterUserComponent;
|
||||
let fixture: ComponentFixture<FilterUserComponent>;
|
||||
let component: FilterProjectComponent;
|
||||
let fixture: ComponentFixture<FilterProjectComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [FilterUserComponent],
|
||||
declarations: [FilterProjectComponent],
|
||||
}).compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FilterUserComponent);
|
||||
fixture = TestBed.createComponent(FilterProjectComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
@@ -1,8 +1,49 @@
|
||||
import { Component, ElementRef, NgZone } from '@angular/core';
|
||||
import { TestBed, ComponentFixture } from '@angular/core/testing';
|
||||
import { InputDirective } from './input.directive';
|
||||
import { Platform } from '@angular/cdk/platform';
|
||||
import { NgControl, NgForm, FormGroupDirective } from '@angular/forms';
|
||||
import { ErrorStateMatcher } from '@angular/material/core';
|
||||
import { AutofillMonitor } from '@angular/cdk/text-field';
|
||||
import { MatFormField } from '@angular/material/form-field';
|
||||
import { MAT_INPUT_VALUE_ACCESSOR } from '@angular/material/input';
|
||||
import { of } from 'rxjs';
|
||||
import { By } from '@angular/platform-browser';
|
||||
|
||||
@Component({
|
||||
template: `<input appInputDirective />`,
|
||||
})
|
||||
class TestHostComponent {}
|
||||
|
||||
describe('InputDirective', () => {
|
||||
let fixture: ComponentFixture<TestHostComponent>;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [InputDirective, TestHostComponent],
|
||||
providers: [
|
||||
{ provide: ElementRef, useValue: new ElementRef(document.createElement('input')) },
|
||||
Platform,
|
||||
{ provide: NgControl, useValue: null },
|
||||
{ provide: NgForm, useValue: null },
|
||||
{ provide: FormGroupDirective, useValue: null },
|
||||
ErrorStateMatcher,
|
||||
{ provide: MAT_INPUT_VALUE_ACCESSOR, useValue: null },
|
||||
{
|
||||
provide: AutofillMonitor,
|
||||
useValue: { monitor: () => of(), stopMonitoring: () => {} },
|
||||
},
|
||||
NgZone,
|
||||
{ provide: MatFormField, useValue: null },
|
||||
],
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(TestHostComponent);
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create an instance', () => {
|
||||
const directive = new InputDirective();
|
||||
expect(directive).toBeTruthy();
|
||||
const directiveEl = fixture.debugElement.query(By.directive(InputDirective));
|
||||
expect(directiveEl).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
@@ -1,19 +1,19 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { AvatarComponent } from './avatar.component';
|
||||
import { LabelComponent } from './label.component';
|
||||
|
||||
describe('AvatarComponent', () => {
|
||||
let component: AvatarComponent;
|
||||
let fixture: ComponentFixture<AvatarComponent>;
|
||||
let component: LabelComponent;
|
||||
let fixture: ComponentFixture<LabelComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [AvatarComponent],
|
||||
declarations: [LabelComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(AvatarComponent);
|
||||
fixture = TestBed.createComponent(LabelComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
@@ -2,14 +2,12 @@ import { Component, Injector, Input, OnDestroy, OnInit, Type } from '@angular/co
|
||||
import { AbstractControl, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { Duration } from 'google-protobuf/google/protobuf/duration_pb';
|
||||
import { firstValueFrom, forkJoin, from, Observable, of, Subject, take } from 'rxjs';
|
||||
import { forkJoin, from, of, Subject, take } from 'rxjs';
|
||||
import {
|
||||
GetLoginPolicyResponse as AdminGetLoginPolicyResponse,
|
||||
UpdateLoginPolicyRequest,
|
||||
UpdateLoginPolicyResponse,
|
||||
} from 'src/app/proto/generated/zitadel/admin_pb';
|
||||
import {
|
||||
AddCustomLoginPolicyRequest,
|
||||
GetLoginPolicyResponse as MgmtGetLoginPolicyResponse,
|
||||
UpdateCustomLoginPolicyRequest,
|
||||
} from 'src/app/proto/generated/zitadel/management_pb';
|
||||
@@ -24,8 +22,7 @@ import { InfoSectionType } from '../../info-section/info-section.component';
|
||||
import { WarnDialogComponent } from '../../warn-dialog/warn-dialog.component';
|
||||
import { PolicyComponentServiceType } from '../policy-component-types.enum';
|
||||
import { LoginMethodComponentType } from './factor-table/factor-table.component';
|
||||
import { catchError, map, takeUntil } from 'rxjs/operators';
|
||||
import { error } from 'console';
|
||||
import { map, takeUntil } from 'rxjs/operators';
|
||||
import { LoginPolicyService } from '../../../services/login-policy.service';
|
||||
|
||||
const minValueValidator = (minValue: number) => (control: AbstractControl) => {
|
||||
|
@@ -1,19 +1,19 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { LoginPolicyComponent } from './login-policy.component';
|
||||
import { MessageTextsComponent } from './message-texts.component';
|
||||
|
||||
describe('LoginPolicyComponent', () => {
|
||||
let component: LoginPolicyComponent;
|
||||
let fixture: ComponentFixture<LoginPolicyComponent>;
|
||||
let component: MessageTextsComponent;
|
||||
let fixture: ComponentFixture<MessageTextsComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [LoginPolicyComponent],
|
||||
declarations: [MessageTextsComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(LoginPolicyComponent);
|
||||
fixture = TestBed.createComponent(MessageTextsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
@@ -1,19 +1,19 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { PasswordComplexityPolicyComponent } from './password-complexity-policy.component';
|
||||
import { NotificationPolicyComponent } from './notification-policy.component';
|
||||
|
||||
describe('PasswordComplexityPolicyComponent', () => {
|
||||
let component: PasswordComplexityPolicyComponent;
|
||||
let fixture: ComponentFixture<PasswordComplexityPolicyComponent>;
|
||||
let component: NotificationPolicyComponent;
|
||||
let fixture: ComponentFixture<NotificationPolicyComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [PasswordComplexityPolicyComponent],
|
||||
declarations: [NotificationPolicyComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(PasswordComplexityPolicyComponent);
|
||||
fixture = TestBed.createComponent(NotificationPolicyComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
@@ -1,19 +1,19 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { PasswordDialogComponent } from './password-dialog-sms-provider.component';
|
||||
import { PasswordDialogSMSProviderComponent } from './password-dialog-sms-provider.component';
|
||||
|
||||
describe('PasswordDialogComponent', () => {
|
||||
let component: PasswordDialogComponent;
|
||||
let fixture: ComponentFixture<PasswordDialogComponent>;
|
||||
let component: PasswordDialogSMSProviderComponent;
|
||||
let fixture: ComponentFixture<PasswordDialogSMSProviderComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [PasswordDialogComponent],
|
||||
declarations: [PasswordDialogSMSProviderComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(PasswordDialogComponent);
|
||||
fixture = TestBed.createComponent(PasswordDialogSMSProviderComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
@@ -1,19 +1,19 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { ProviderOAuthComponent } from './provider-oauth.component';
|
||||
import { ProviderGithubESComponent } from './provider-github-es.component';
|
||||
|
||||
describe('ProviderOAuthComponent', () => {
|
||||
let component: ProviderOAuthComponent;
|
||||
let fixture: ComponentFixture<ProviderOAuthComponent>;
|
||||
let component: ProviderGithubESComponent;
|
||||
let fixture: ComponentFixture<ProviderGithubESComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ProviderOAuthComponent],
|
||||
declarations: [ProviderGithubESComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ProviderOAuthComponent);
|
||||
fixture = TestBed.createComponent(ProviderGithubESComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
@@ -1,19 +1,19 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { ProviderGoogleComponent } from './provider-google.component';
|
||||
import { ProviderGitlabSelfHostedComponent } from './provider-gitlab-self-hosted.component';
|
||||
|
||||
describe('ProviderGoogleComponent', () => {
|
||||
let component: ProviderGoogleComponent;
|
||||
let fixture: ComponentFixture<ProviderGoogleComponent>;
|
||||
let component: ProviderGitlabSelfHostedComponent;
|
||||
let fixture: ComponentFixture<ProviderGitlabSelfHostedComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ProviderGoogleComponent],
|
||||
declarations: [ProviderGitlabSelfHostedComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ProviderGoogleComponent);
|
||||
fixture = TestBed.createComponent(ProviderGitlabSelfHostedComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
@@ -1,19 +1,19 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { ProviderGoogleComponent } from './provider-google.component';
|
||||
import { ProviderGitlabComponent } from './provider-gitlab.component';
|
||||
|
||||
describe('ProviderGoogleComponent', () => {
|
||||
let component: ProviderGoogleComponent;
|
||||
let fixture: ComponentFixture<ProviderGoogleComponent>;
|
||||
let component: ProviderGitlabComponent;
|
||||
let fixture: ComponentFixture<ProviderGitlabComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ProviderGoogleComponent],
|
||||
declarations: [ProviderGitlabComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ProviderGoogleComponent);
|
||||
fixture = TestBed.createComponent(ProviderGitlabComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
@@ -1,19 +1,19 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { ShowKeyDialogComponent } from './show-key-dialog.component';
|
||||
import { ShowTokenDialogComponent } from './show-token-dialog.component';
|
||||
|
||||
describe('ShowKeyDialogComponent', () => {
|
||||
let component: ShowKeyDialogComponent;
|
||||
let fixture: ComponentFixture<ShowKeyDialogComponent>;
|
||||
let component: ShowTokenDialogComponent;
|
||||
let fixture: ComponentFixture<ShowTokenDialogComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ShowKeyDialogComponent],
|
||||
declarations: [ShowTokenDialogComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ShowKeyDialogComponent);
|
||||
fixture = TestBed.createComponent(ShowTokenDialogComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
@@ -1,19 +1,19 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { IdpTableComponent } from './smtp-table.component';
|
||||
import { SMTPTableComponent } from './smtp-table.component';
|
||||
|
||||
describe('UserTableComponent', () => {
|
||||
let component: IdpTableComponent;
|
||||
let fixture: ComponentFixture<IdpTableComponent>;
|
||||
let component: SMTPTableComponent;
|
||||
let fixture: ComponentFixture<SMTPTableComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [IdpTableComponent],
|
||||
declarations: [SMTPTableComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(IdpTableComponent);
|
||||
fixture = TestBed.createComponent(SMTPTableComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
@@ -1,19 +1,19 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { AddKeyDialogComponent } from './add-key-dialog.component';
|
||||
import { AddActionDialogComponent } from './add-action-dialog.component';
|
||||
|
||||
describe('AddKeyDialogComponent', () => {
|
||||
let component: AddKeyDialogComponent;
|
||||
let fixture: ComponentFixture<AddKeyDialogComponent>;
|
||||
let component: AddActionDialogComponent;
|
||||
let fixture: ComponentFixture<AddActionDialogComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [AddKeyDialogComponent],
|
||||
declarations: [AddActionDialogComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(AddKeyDialogComponent);
|
||||
fixture = TestBed.createComponent(AddActionDialogComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
@@ -1,19 +1,19 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { AddKeyDialogComponent } from './add-key-dialog.component';
|
||||
import { AddFlowDialogComponent } from './add-flow-dialog.component';
|
||||
|
||||
describe('AddKeyDialogComponent', () => {
|
||||
let component: AddKeyDialogComponent;
|
||||
let fixture: ComponentFixture<AddKeyDialogComponent>;
|
||||
let component: AddFlowDialogComponent;
|
||||
let fixture: ComponentFixture<AddFlowDialogComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [AddKeyDialogComponent],
|
||||
declarations: [AddFlowDialogComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(AddKeyDialogComponent);
|
||||
fixture = TestBed.createComponent(AddFlowDialogComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<h1 mat-dialog-title>
|
||||
<span class="title">{{ 'USER.MFA.DIALOG.ADD_MFA_TITLE' | translate }} {{ data?.number }}</span>
|
||||
<span class="title">{{ 'USER.MFA.DIALOG.ADD_MFA_TITLE' | translate }}</span>
|
||||
</h1>
|
||||
<div mat-dialog-content>
|
||||
<ng-container *ngIf="selectedType === undefined">
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
<div class="type-selection">
|
||||
<button
|
||||
*ngIf="data.otp$ | async"
|
||||
mat-stroked-button
|
||||
[disabled]="data.otpDisabled$ | async"
|
||||
(click)="selectType(AuthFactorType.OTP)"
|
||||
@@ -56,7 +57,7 @@
|
||||
<span>{{ 'USER.MFA.OTP' | translate }}</span>
|
||||
</div>
|
||||
</button>
|
||||
<button mat-stroked-button (click)="selectType(AuthFactorType.U2F)">
|
||||
<button *ngIf="data.u2f$ | async" mat-stroked-button (click)="selectType(AuthFactorType.U2F)">
|
||||
<div class="u2f-btn">
|
||||
<div class="icon-row">
|
||||
<svg
|
||||
@@ -78,6 +79,7 @@
|
||||
</div>
|
||||
</button>
|
||||
<button
|
||||
*ngIf="data.otpSms$ | async"
|
||||
[disabled]="!data.phoneVerified || (data.otpSmsDisabled$ | async)"
|
||||
mat-stroked-button
|
||||
(click)="selectType(AuthFactorType.OTPSMS)"
|
||||
@@ -110,7 +112,12 @@
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
<button [disabled]="data.otpEmailDisabled$ | async" mat-stroked-button (click)="selectType(AuthFactorType.OTPEMAIL)">
|
||||
<button
|
||||
*ngIf="data.otpEmail$ | async"
|
||||
[disabled]="data.otpEmailDisabled$ | async"
|
||||
mat-stroked-button
|
||||
(click)="selectType(AuthFactorType.OTPEMAIL)"
|
||||
>
|
||||
<div class="otp-btn">
|
||||
<div class="icon-row">
|
||||
<svg
|
||||
|
@@ -2,6 +2,7 @@ import { Component, Inject } from '@angular/core';
|
||||
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { take } from 'rxjs/operators';
|
||||
import { Observable } from 'rxjs';
|
||||
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
@@ -16,6 +17,17 @@ export enum AuthFactorType {
|
||||
OTPEMAIL,
|
||||
}
|
||||
|
||||
export type AddAuthFactorDialogData = {
|
||||
otp$: Observable<boolean>;
|
||||
u2f$: Observable<boolean>;
|
||||
otpSms$: Observable<boolean>;
|
||||
otpEmail$: Observable<boolean>;
|
||||
otpDisabled$: Observable<boolean>;
|
||||
otpSmsDisabled$: Observable<boolean>;
|
||||
otpEmailDisabled$: Observable<boolean>;
|
||||
phoneVerified: boolean;
|
||||
};
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-auth-factor-dialog',
|
||||
templateUrl: './auth-factor-dialog.component.html',
|
||||
@@ -44,7 +56,7 @@ export class AuthFactorDialogComponent {
|
||||
private toast: ToastService,
|
||||
private translate: TranslateService,
|
||||
public dialogRef: MatDialogRef<AuthFactorDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any,
|
||||
@Inject(MAT_DIALOG_DATA) public data: AddAuthFactorDialogData,
|
||||
) {}
|
||||
|
||||
closeDialog(code: string = ''): void {
|
||||
|
@@ -1,24 +1,147 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { of } from 'rxjs';
|
||||
import { AuthUserMfaComponent } from './auth-user-mfa.component';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { NewAuthService } from 'src/app/services/new-auth.service';
|
||||
import { SecondFactorType } from 'src/app/proto/generated/zitadel/policy_pb';
|
||||
import { CardComponent } from 'src/app/modules/card/card.component';
|
||||
import { RefreshTableComponent } from 'src/app/modules/refresh-table/refresh-table.component';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatTableModule } from '@angular/material/table';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { AuthFactor, AuthFactorState } from '@zitadel/proto/zitadel/user_pb';
|
||||
|
||||
describe('AuthUserMfaComponent', () => {
|
||||
let component: AuthUserMfaComponent;
|
||||
let fixture: ComponentFixture<AuthUserMfaComponent>;
|
||||
// Create a test host component that extends the original component
|
||||
class TestHostComponent extends AuthUserMfaComponent {
|
||||
// Expose protected properties for testing
|
||||
public getOtpEmailDisabled$() {
|
||||
return this.otpEmailDisabled$;
|
||||
}
|
||||
|
||||
public getOtpDisabled$() {
|
||||
return this.otpDisabled$;
|
||||
}
|
||||
|
||||
public getOtpSmsDisabled$() {
|
||||
return this.otpSmsDisabled$;
|
||||
}
|
||||
}
|
||||
|
||||
let component: TestHostComponent;
|
||||
let fixture: ComponentFixture<TestHostComponent>;
|
||||
let serviceStub: Partial<NewAuthService>;
|
||||
let toastStub: Partial<ToastService>;
|
||||
let dialogStub: Partial<MatDialog>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
// Create stubs for required services
|
||||
serviceStub = {
|
||||
listMyMultiFactors: jasmine.createSpy('listMyMultiFactors').and.returnValue(
|
||||
Promise.resolve({
|
||||
result: [
|
||||
{ type: { case: 'otp' }, state: AuthFactorState.READY, $typeName: 'zitadel.user.v1.AuthFactor' } as AuthFactor,
|
||||
{
|
||||
type: { case: 'otpSms' },
|
||||
state: AuthFactorState.READY,
|
||||
$typeName: 'zitadel.user.v1.AuthFactor',
|
||||
} as AuthFactor,
|
||||
{
|
||||
type: { case: 'otpEmail' },
|
||||
state: AuthFactorState.READY,
|
||||
$typeName: 'zitadel.user.v1.AuthFactor',
|
||||
} as AuthFactor,
|
||||
],
|
||||
}),
|
||||
),
|
||||
getMyLoginPolicy: jasmine.createSpy('getMyLoginPolicy').and.returnValue(
|
||||
Promise.resolve({
|
||||
policy: {
|
||||
secondFactorsList: [
|
||||
SecondFactorType.SECOND_FACTOR_TYPE_OTP,
|
||||
SecondFactorType.SECOND_FACTOR_TYPE_U2F,
|
||||
SecondFactorType.SECOND_FACTOR_TYPE_OTP_EMAIL,
|
||||
SecondFactorType.SECOND_FACTOR_TYPE_OTP_SMS,
|
||||
],
|
||||
},
|
||||
}),
|
||||
),
|
||||
removeMyMultiFactorOTP: jasmine.createSpy('removeMyMultiFactorOTP').and.returnValue(Promise.resolve()),
|
||||
removeMyMultiFactorU2F: jasmine.createSpy('removeMyMultiFactorU2F').and.returnValue(Promise.resolve()),
|
||||
removeMyAuthFactorOTPEmail: jasmine.createSpy('removeMyAuthFactorOTPEmail').and.returnValue(Promise.resolve()),
|
||||
removeMyAuthFactorOTPSMS: jasmine.createSpy('removeMyAuthFactorOTPSMS').and.returnValue(Promise.resolve()),
|
||||
};
|
||||
|
||||
toastStub = {
|
||||
showInfo: jasmine.createSpy('showInfo'),
|
||||
showError: jasmine.createSpy('showError'),
|
||||
};
|
||||
|
||||
dialogStub = {
|
||||
// Opened dialog returns a truthy value after closing
|
||||
open: jasmine.createSpy('open').and.returnValue({
|
||||
afterClosed: () => of(true),
|
||||
}),
|
||||
};
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [AuthUserMfaComponent],
|
||||
declarations: [TestHostComponent, CardComponent, RefreshTableComponent], // Use TestHostComponent instead
|
||||
imports: [MatIconModule, TranslateModule.forRoot(), MatTooltipModule, MatTableModule, BrowserAnimationsModule],
|
||||
providers: [
|
||||
{ provide: NewAuthService, useValue: serviceStub },
|
||||
{ provide: ToastService, useValue: toastStub },
|
||||
{ provide: MatDialog, useValue: dialogStub },
|
||||
],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(AuthUserMfaComponent);
|
||||
fixture = TestBed.createComponent(TestHostComponent); // Use TestHostComponent
|
||||
component = fixture.componentInstance;
|
||||
// Optionally set the phoneVerified input if needed by your tests
|
||||
component.phoneVerified = true;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should call getMFAs and update dataSource and disable flags', async () => {
|
||||
// Call the method and wait for the Promise resolution
|
||||
await component.getMFAs();
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(serviceStub.listMyMultiFactors).toHaveBeenCalled();
|
||||
// Our stub returns 3 items
|
||||
expect(component.dataSource.data.length).toBe(3);
|
||||
|
||||
// Use the public getter methods to access protected properties
|
||||
component.getOtpDisabled$().subscribe((value) => {
|
||||
expect(value).toBeTrue();
|
||||
});
|
||||
component.getOtpSmsDisabled$().subscribe((value) => {
|
||||
expect(value).toBeTrue();
|
||||
});
|
||||
component.getOtpEmailDisabled$().subscribe((value) => {
|
||||
expect(value).toBeTrue();
|
||||
});
|
||||
});
|
||||
|
||||
it('should call deleteMFA and remove OTP factor', async () => {
|
||||
// OTP is set
|
||||
const factor = {
|
||||
type: { case: 'otp' },
|
||||
state: AuthFactorState.READY,
|
||||
$typeName: 'zitadel.user.v1.AuthFactor',
|
||||
} as AuthFactor;
|
||||
await component.deleteMFA(factor);
|
||||
|
||||
// Verify that the service method for OTP removal was called
|
||||
expect(serviceStub.removeMyMultiFactorOTP).toHaveBeenCalled();
|
||||
expect(serviceStub.listMyMultiFactors).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
@@ -4,12 +4,12 @@ import { MatSort } from '@angular/material/sort';
|
||||
import { MatTable, MatTableDataSource } from '@angular/material/table';
|
||||
import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { WarnDialogComponent } from 'src/app/modules/warn-dialog/warn-dialog.component';
|
||||
import { AuthFactor, AuthFactorState } from 'src/app/proto/generated/zitadel/user_pb';
|
||||
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
||||
import { AuthFactorState } from 'src/app/proto/generated/zitadel/user_pb';
|
||||
import { NewAuthService } from 'src/app/services/new-auth.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
import { AuthFactorDialogComponent } from '../auth-factor-dialog/auth-factor-dialog.component';
|
||||
|
||||
import { AddAuthFactorDialogData, AuthFactorDialogComponent } from '../auth-factor-dialog/auth-factor-dialog.component';
|
||||
import { AuthFactor } from '@zitadel/proto/zitadel/user_pb';
|
||||
import { SecondFactorType } from '@zitadel/proto/zitadel/policy_pb';
|
||||
export interface WebAuthNOptions {
|
||||
challenge: string;
|
||||
rp: { name: string; id: string };
|
||||
@@ -30,26 +30,31 @@ export class AuthUserMfaComponent implements OnInit, OnDestroy {
|
||||
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
||||
|
||||
@ViewChild(MatTable) public table!: MatTable<AuthFactor.AsObject>;
|
||||
@ViewChild(MatTable) public table!: MatTable<AuthFactor>;
|
||||
@ViewChild(MatSort) public sort!: MatSort;
|
||||
@Input() public phoneVerified: boolean = false;
|
||||
public dataSource: MatTableDataSource<AuthFactor.AsObject> = new MatTableDataSource<AuthFactor.AsObject>([]);
|
||||
|
||||
public AuthFactorState: any = AuthFactorState;
|
||||
public dataSource: MatTableDataSource<AuthFactor> = new MatTableDataSource<AuthFactor>([]);
|
||||
|
||||
public error: string = '';
|
||||
public otpDisabled$ = new BehaviorSubject<boolean>(true);
|
||||
public otpSmsDisabled$ = new BehaviorSubject<boolean>(true);
|
||||
public otpEmailDisabled$ = new BehaviorSubject<boolean>(true);
|
||||
protected error: string = '';
|
||||
|
||||
protected otpAvailable$ = new BehaviorSubject<boolean>(false);
|
||||
protected u2fAvailable$ = new BehaviorSubject<boolean>(false);
|
||||
protected otpSmsAvailable$ = new BehaviorSubject<boolean>(false);
|
||||
protected otpEmailAvailable$ = new BehaviorSubject<boolean>(false);
|
||||
protected otpDisabled$ = new BehaviorSubject<boolean>(true);
|
||||
protected otpSmsDisabled$ = new BehaviorSubject<boolean>(true);
|
||||
protected otpEmailDisabled$ = new BehaviorSubject<boolean>(true);
|
||||
|
||||
constructor(
|
||||
private service: GrpcAuthService,
|
||||
private toast: ToastService,
|
||||
private dialog: MatDialog,
|
||||
private readonly service: NewAuthService,
|
||||
private readonly toast: ToastService,
|
||||
private readonly dialog: MatDialog,
|
||||
) {}
|
||||
|
||||
public ngOnInit(): void {
|
||||
this.getMFAs();
|
||||
this.applyOrgPolicy();
|
||||
}
|
||||
|
||||
public ngOnDestroy(): void {
|
||||
@@ -57,13 +62,19 @@ export class AuthUserMfaComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
public addAuthFactor(): void {
|
||||
const dialogRef = this.dialog.open(AuthFactorDialogComponent, {
|
||||
data: {
|
||||
const data: AddAuthFactorDialogData = {
|
||||
otp$: this.otpAvailable$,
|
||||
u2f$: this.u2fAvailable$,
|
||||
otpSms$: this.otpSmsAvailable$,
|
||||
otpEmail$: this.otpEmailAvailable$,
|
||||
otpDisabled$: this.otpDisabled$,
|
||||
otpSmsDisabled$: this.otpSmsDisabled$,
|
||||
otpEmailDisabled$: this.otpEmailDisabled$,
|
||||
phoneVerified: this.phoneVerified,
|
||||
},
|
||||
} as const;
|
||||
|
||||
const dialogRef = this.dialog.open(AuthFactorDialogComponent, {
|
||||
data: data,
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(() => {
|
||||
@@ -75,48 +86,32 @@ export class AuthUserMfaComponent implements OnInit, OnDestroy {
|
||||
this.service
|
||||
.listMyMultiFactors()
|
||||
.then((mfas) => {
|
||||
const list = mfas.resultList;
|
||||
const list: AuthFactor[] = mfas.result;
|
||||
this.dataSource = new MatTableDataSource(list);
|
||||
this.dataSource.sort = this.sort;
|
||||
|
||||
const index = list.findIndex((mfa) => mfa.otp);
|
||||
if (index === -1) {
|
||||
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);
|
||||
}
|
||||
this.disableAuthFactor(list, 'otp', this.otpDisabled$);
|
||||
this.disableAuthFactor(list, 'otpSms', this.otpSmsDisabled$);
|
||||
this.disableAuthFactor(list, 'otpEmail', this.otpEmailDisabled$);
|
||||
})
|
||||
.catch((error) => {
|
||||
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);
|
||||
public applyOrgPolicy(): void {
|
||||
this.service.getMyLoginPolicy().then((resp) => {
|
||||
if (resp && resp.policy) {
|
||||
const secondFactors = resp.policy?.secondFactors;
|
||||
this.displayAuthFactorBasedOnPolicy(secondFactors, SecondFactorType.OTP, this.otpAvailable$);
|
||||
this.displayAuthFactorBasedOnPolicy(secondFactors, SecondFactorType.U2F, this.u2fAvailable$);
|
||||
this.displayAuthFactorBasedOnPolicy(secondFactors, SecondFactorType.OTP_EMAIL, this.otpEmailAvailable$);
|
||||
this.displayAuthFactorBasedOnPolicy(secondFactors, SecondFactorType.OTP_SMS, this.otpSmsAvailable$);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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): void {
|
||||
const dialogRef = this.dialog.open(WarnDialogComponent, {
|
||||
data: {
|
||||
confirmKey: 'ACTIONS.DELETE',
|
||||
@@ -129,7 +124,7 @@ export class AuthUserMfaComponent implements OnInit, OnDestroy {
|
||||
|
||||
dialogRef.afterClosed().subscribe((resp) => {
|
||||
if (resp) {
|
||||
if (factor.otp) {
|
||||
if (factor.type.case === 'otp') {
|
||||
this.service
|
||||
.removeMyMultiFactorOTP()
|
||||
.then(() => {
|
||||
@@ -141,9 +136,9 @@ export class AuthUserMfaComponent implements OnInit, OnDestroy {
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
} else if (factor.u2f) {
|
||||
} else if (factor.type.case === 'u2f') {
|
||||
this.service
|
||||
.removeMyMultiFactorU2F(factor.u2f.id)
|
||||
.removeMyMultiFactorU2F(factor.type.value.id)
|
||||
.then(() => {
|
||||
this.toast.showInfo('USER.TOAST.U2FREMOVED', true);
|
||||
|
||||
@@ -153,7 +148,7 @@ export class AuthUserMfaComponent implements OnInit, OnDestroy {
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
} else if (factor.otpEmail) {
|
||||
} else if (factor.type.case === 'otpEmail') {
|
||||
this.service
|
||||
.removeMyAuthFactorOTPEmail()
|
||||
.then(() => {
|
||||
@@ -165,7 +160,7 @@ export class AuthUserMfaComponent implements OnInit, OnDestroy {
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
} else if (factor.otpSms) {
|
||||
} else if (factor.type.case === 'otpSms') {
|
||||
this.service
|
||||
.removeMyAuthFactorOTPSMS()
|
||||
.then(() => {
|
||||
@@ -181,4 +176,22 @@ export class AuthUserMfaComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private cleanupList(): void {
|
||||
this.dataSource.data = this.dataSource.data.filter((mfa: AuthFactor) => {
|
||||
return mfa.type.case;
|
||||
});
|
||||
}
|
||||
|
||||
private disableAuthFactor(mfas: AuthFactor[], key: string, subject: BehaviorSubject<boolean>): void {
|
||||
subject.next(mfas.some((mfa) => mfa.type.case === key));
|
||||
}
|
||||
|
||||
private displayAuthFactorBasedOnPolicy(
|
||||
factors: SecondFactorType[],
|
||||
factor: SecondFactorType,
|
||||
subject: BehaviorSubject<boolean>,
|
||||
): void {
|
||||
subject.next(factors.some((f) => f === factor));
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,7 @@ import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { MatDialog } from '@angular/material/dialog';
|
||||
import { WarnDialogComponent } from 'src/app/modules/warn-dialog/warn-dialog.component';
|
||||
|
||||
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
||||
import { NewAuthService } from 'src/app/services/new-auth.service';
|
||||
import { CodeDialogComponent } from '../auth-user-detail/code-dialog/code-dialog.component';
|
||||
import { EditDialogType } from '../auth-user-detail/edit-dialog/edit-dialog.component';
|
||||
import { HumanUser, UserState } from '@zitadel/proto/zitadel/user/v2/user_pb';
|
||||
@@ -28,12 +28,12 @@ export class ContactComponent {
|
||||
public EditDialogType: any = EditDialogType;
|
||||
constructor(
|
||||
private dialog: MatDialog,
|
||||
private authService: GrpcAuthService,
|
||||
private authService: NewAuthService,
|
||||
) {}
|
||||
|
||||
async emitDeletePhone(): Promise<void> {
|
||||
const { resultList } = await this.authService.listMyMultiFactors();
|
||||
const hasSMSOTP = !!resultList.find((mfa) => mfa.otpSms);
|
||||
const { result } = await this.authService.listMyMultiFactors();
|
||||
const hasSMSOTP = !!result.some((mfa) => mfa.type.case === 'otpSms');
|
||||
|
||||
const dialogRef = this.dialog.open(WarnDialogComponent, {
|
||||
data: {
|
||||
|
@@ -1,19 +1,19 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { DetailFormComponent } from './detail-form.component';
|
||||
import { DetailFormMachineComponent } from './detail-form-machine.component';
|
||||
|
||||
describe('DetailFormComponent', () => {
|
||||
let component: DetailFormComponent;
|
||||
let fixture: ComponentFixture<DetailFormComponent>;
|
||||
let component: DetailFormMachineComponent;
|
||||
let fixture: ComponentFixture<DetailFormMachineComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [DetailFormComponent],
|
||||
declarations: [DetailFormMachineComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(DetailFormComponent);
|
||||
fixture = TestBed.createComponent(DetailFormMachineComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
@@ -1,19 +1,19 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { AuthPasswordlessComponent } from './auth-passwordless.component';
|
||||
import { PasswordlessComponent } from './passwordless.component';
|
||||
|
||||
describe('AuthPasswordlessComponent', () => {
|
||||
let component: AuthPasswordlessComponent;
|
||||
let fixture: ComponentFixture<AuthPasswordlessComponent>;
|
||||
let component: PasswordlessComponent;
|
||||
let fixture: ComponentFixture<PasswordlessComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [AuthPasswordlessComponent],
|
||||
declarations: [PasswordlessComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(AuthPasswordlessComponent);
|
||||
fixture = TestBed.createComponent(PasswordlessComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
@@ -31,8 +31,6 @@ import {
|
||||
GetMyEmailRequest,
|
||||
GetMyEmailResponse,
|
||||
GetMyLabelPolicyRequest,
|
||||
GetMyLoginPolicyRequest,
|
||||
GetMyLoginPolicyResponse,
|
||||
GetMyPasswordComplexityPolicyRequest,
|
||||
GetMyPasswordComplexityPolicyResponse,
|
||||
GetMyPhoneRequest,
|
||||
@@ -42,8 +40,6 @@ import {
|
||||
GetMyProfileResponse,
|
||||
GetMyUserRequest,
|
||||
GetMyUserResponse,
|
||||
ListMyAuthFactorsRequest,
|
||||
ListMyAuthFactorsResponse,
|
||||
ListMyLinkedIDPsRequest,
|
||||
ListMyLinkedIDPsResponse,
|
||||
ListMyMembershipsRequest,
|
||||
@@ -62,14 +58,6 @@ import {
|
||||
ListMyUserSessionsResponse,
|
||||
ListMyZitadelPermissionsRequest,
|
||||
ListMyZitadelPermissionsResponse,
|
||||
RemoveMyAuthFactorOTPEmailRequest,
|
||||
RemoveMyAuthFactorOTPEmailResponse,
|
||||
RemoveMyAuthFactorOTPRequest,
|
||||
RemoveMyAuthFactorOTPResponse,
|
||||
RemoveMyAuthFactorOTPSMSRequest,
|
||||
RemoveMyAuthFactorOTPSMSResponse,
|
||||
RemoveMyAuthFactorU2FRequest,
|
||||
RemoveMyAuthFactorU2FResponse,
|
||||
RemoveMyAvatarRequest,
|
||||
RemoveMyAvatarResponse,
|
||||
RemoveMyLinkedIDPRequest,
|
||||
@@ -357,10 +345,6 @@ export class GrpcAuthService {
|
||||
return this.grpcService.auth.getMyUser(new GetMyUserRequest(), null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public listMyMultiFactors(): Promise<ListMyAuthFactorsResponse.AsObject> {
|
||||
return this.grpcService.auth.listMyAuthFactors(new ListMyAuthFactorsRequest(), null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public async revalidateOrgs() {
|
||||
const orgs = (await this.listMyProjectOrgs(ORG_LIMIT, 0)).resultList;
|
||||
this.cachedOrgs.next(orgs);
|
||||
@@ -488,11 +472,6 @@ export class GrpcAuthService {
|
||||
return this.grpcService.auth.resendMyEmailVerification(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public getMyLoginPolicy(): Promise<GetMyLoginPolicyResponse.AsObject> {
|
||||
const req = new GetMyLoginPolicyRequest();
|
||||
return this.grpcService.auth.getMyLoginPolicy(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public removeMyPhone(): Promise<RemoveMyPhoneResponse.AsObject> {
|
||||
return this.grpcService.auth.removeMyPhone(new RemoveMyPhoneRequest(), null).then((resp) => resp.toObject());
|
||||
}
|
||||
@@ -576,12 +555,6 @@ export class GrpcAuthService {
|
||||
return this.grpcService.auth.addMyAuthFactorU2F(new AddMyAuthFactorU2FRequest(), null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public removeMyMultiFactorU2F(tokenId: string): Promise<RemoveMyAuthFactorU2FResponse.AsObject> {
|
||||
const req = new RemoveMyAuthFactorU2FRequest();
|
||||
req.setTokenId(tokenId);
|
||||
return this.grpcService.auth.removeMyAuthFactorU2F(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public verifyMyMultiFactorU2F(credential: string, tokenname: string): Promise<VerifyMyAuthFactorU2FResponse.AsObject> {
|
||||
const req = new VerifyMyAuthFactorU2FRequest();
|
||||
const verification = new WebAuthNVerification();
|
||||
@@ -626,24 +599,6 @@ export class GrpcAuthService {
|
||||
return this.grpcService.auth.addMyPasswordlessLink(req, null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public removeMyMultiFactorOTP(): Promise<RemoveMyAuthFactorOTPResponse.AsObject> {
|
||||
return this.grpcService.auth
|
||||
.removeMyAuthFactorOTP(new RemoveMyAuthFactorOTPRequest(), null)
|
||||
.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> {
|
||||
const req = new VerifyMyAuthFactorOTPRequest();
|
||||
req.setCode(code);
|
||||
|
@@ -1,9 +1,22 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { GrpcService } from './grpc.service';
|
||||
import { create } from '@bufbuild/protobuf';
|
||||
import {
|
||||
AddMyAuthFactorOTPSMSResponse,
|
||||
GetMyLoginPolicyResponse,
|
||||
GetMyLoginPolicyRequestSchema,
|
||||
GetMyPasswordComplexityPolicyResponse,
|
||||
GetMyUserResponse,
|
||||
ListMyAuthFactorsRequestSchema,
|
||||
ListMyAuthFactorsResponse,
|
||||
RemoveMyAuthFactorOTPEmailRequestSchema,
|
||||
RemoveMyAuthFactorOTPEmailResponse,
|
||||
RemoveMyAuthFactorOTPRequestSchema,
|
||||
RemoveMyAuthFactorOTPResponse,
|
||||
RemoveMyAuthFactorU2FRequestSchema,
|
||||
RemoveMyAuthFactorU2FResponse,
|
||||
RemoveMyAuthFactorOTPSMSRequestSchema,
|
||||
RemoveMyAuthFactorOTPSMSResponse,
|
||||
ListMyMetadataResponse,
|
||||
VerifyMyPhoneResponse,
|
||||
} from '@zitadel/proto/zitadel/auth_pb';
|
||||
@@ -30,6 +43,30 @@ export class NewAuthService {
|
||||
return this.grpcService.authNew.listMyMetadata({});
|
||||
}
|
||||
|
||||
public listMyMultiFactors(): Promise<ListMyAuthFactorsResponse> {
|
||||
return this.grpcService.authNew.listMyAuthFactors(create(ListMyAuthFactorsRequestSchema), null);
|
||||
}
|
||||
|
||||
public removeMyAuthFactorOTPSMS(): Promise<RemoveMyAuthFactorOTPSMSResponse> {
|
||||
return this.grpcService.authNew.removeMyAuthFactorOTPSMS(create(RemoveMyAuthFactorOTPSMSRequestSchema), null);
|
||||
}
|
||||
|
||||
public getMyLoginPolicy(): Promise<GetMyLoginPolicyResponse> {
|
||||
return this.grpcService.authNew.getMyLoginPolicy(create(GetMyLoginPolicyRequestSchema), null);
|
||||
}
|
||||
|
||||
public removeMyMultiFactorOTP(): Promise<RemoveMyAuthFactorOTPResponse> {
|
||||
return this.grpcService.authNew.removeMyAuthFactorOTP(create(RemoveMyAuthFactorOTPRequestSchema), null);
|
||||
}
|
||||
|
||||
public removeMyMultiFactorU2F(tokenId: string): Promise<RemoveMyAuthFactorU2FResponse> {
|
||||
return this.grpcService.authNew.removeMyAuthFactorU2F(create(RemoveMyAuthFactorU2FRequestSchema, { tokenId }), null);
|
||||
}
|
||||
|
||||
public removeMyAuthFactorOTPEmail(): Promise<RemoveMyAuthFactorOTPEmailResponse> {
|
||||
return this.grpcService.authNew.removeMyAuthFactorOTPEmail(create(RemoveMyAuthFactorOTPEmailRequestSchema), null);
|
||||
}
|
||||
|
||||
public getMyPasswordComplexityPolicy(): Promise<GetMyPasswordComplexityPolicyResponse> {
|
||||
return this.grpcService.authNew.getMyPasswordComplexityPolicy({});
|
||||
}
|
||||
|
@@ -6038,7 +6038,7 @@ istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0:
|
||||
resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756"
|
||||
integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==
|
||||
|
||||
istanbul-lib-instrument@^5.0.4:
|
||||
istanbul-lib-instrument@^5.0.4, istanbul-lib-instrument@^5.1.0:
|
||||
version "5.2.1"
|
||||
resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d"
|
||||
integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==
|
||||
@@ -6069,7 +6069,16 @@ istanbul-lib-source-maps@^3.0.6:
|
||||
rimraf "^2.6.3"
|
||||
source-map "^0.6.1"
|
||||
|
||||
istanbul-reports@^3.0.2:
|
||||
istanbul-lib-source-maps@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551"
|
||||
integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==
|
||||
dependencies:
|
||||
debug "^4.1.1"
|
||||
istanbul-lib-coverage "^3.0.0"
|
||||
source-map "^0.6.1"
|
||||
|
||||
istanbul-reports@^3.0.2, istanbul-reports@^3.0.5:
|
||||
version "3.1.7"
|
||||
resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.7.tgz#daed12b9e1dca518e15c056e1e537e741280fa0b"
|
||||
integrity sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==
|
||||
@@ -6279,6 +6288,18 @@ karma-coverage-istanbul-reporter@^3.0.3:
|
||||
istanbul-reports "^3.0.2"
|
||||
minimatch "^3.0.4"
|
||||
|
||||
karma-coverage@^2.2.1:
|
||||
version "2.2.1"
|
||||
resolved "https://registry.yarnpkg.com/karma-coverage/-/karma-coverage-2.2.1.tgz#e1cc074f93ace9dc4fb7e7aeca7135879c2e358c"
|
||||
integrity sha512-yj7hbequkQP2qOSb20GuNSIyE//PgJWHwC2IydLE6XRtsnaflv+/OSGNssPjobYUlhVVagy99TQpqUt3vAUG7A==
|
||||
dependencies:
|
||||
istanbul-lib-coverage "^3.2.0"
|
||||
istanbul-lib-instrument "^5.1.0"
|
||||
istanbul-lib-report "^3.0.0"
|
||||
istanbul-lib-source-maps "^4.0.1"
|
||||
istanbul-reports "^3.0.5"
|
||||
minimatch "^3.0.4"
|
||||
|
||||
karma-jasmine-html-reporter@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-2.1.0.tgz#f951ad00b08d61d03595402c914d1a589c4930e3"
|
||||
|
Reference in New Issue
Block a user