mirror of
https://github.com/zitadel/zitadel.git
synced 2024-12-04 23:45:07 +00:00
fix(console-v2): settings permission restriction, u2f naming, asset error handling (#3658)
* fix permission on nav * restrict settings access * fido table * u2f i18n, permission * factor, image fallback Co-authored-by: Livio Amstutz <livio.a@gmail.com>
This commit is contained in:
parent
62c4a4d08d
commit
40d7dba574
@ -116,6 +116,11 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
this.domSanitizer.bypassSecurityTrustResourceUrl('assets/mdi/lightbulb-off-outline.svg'),
|
||||
);
|
||||
|
||||
this.matIconRegistry.addSvgIcon(
|
||||
'usb',
|
||||
this.domSanitizer.bypassSecurityTrustResourceUrl('assets/mdi/usb-flash-drive-outline.svg'),
|
||||
);
|
||||
|
||||
this.matIconRegistry.addSvgIcon('mdi_radar', this.domSanitizer.bypassSecurityTrustResourceUrl('assets/mdi/radar.svg'));
|
||||
|
||||
this.matIconRegistry.addSvgIcon(
|
||||
|
@ -1,12 +1,23 @@
|
||||
<div class="avatar-circle dontcloseonclick" matRipple [matRippleColor]="'#ffffff20'" [matRippleUnbounded]="false"
|
||||
[ngStyle]="{'height': size+'px', 'width': size+'px', 'fontSize': (fontSize-1)+'px','fontWeight': fontWeight, 'background': (themeService.isDarkTheme | async) ? color[900]: color[300], 'color': (themeService.isDarkTheme | async) ? color[200]:color[900]}"
|
||||
[ngClass]="{'active': active}">
|
||||
<ng-container *ngIf="isMachine; else human">
|
||||
<i class="machine-icon las la-robot"></i>
|
||||
</ng-container>
|
||||
<ng-template #human>
|
||||
<span class="dontcloseonclick">{{credentials}}</span>
|
||||
<img class="dontcloseonclick" *ngIf="avatarUrl" [src]="avatarUrl"
|
||||
onerror="this.src='./assets/images/transparent.png';this.onerror='';" />
|
||||
</ng-template>
|
||||
</div>
|
||||
<div
|
||||
class="avatar-circle dontcloseonclick"
|
||||
matRipple
|
||||
[matRippleColor]="'#ffffff20'"
|
||||
[matRippleUnbounded]="false"
|
||||
[ngStyle]="{
|
||||
height: size + 'px',
|
||||
width: size + 'px',
|
||||
fontSize: fontSize - 1 + 'px',
|
||||
fontWeight: fontWeight,
|
||||
background: (themeService.isDarkTheme | async) ? color[900] : color[300],
|
||||
color: (themeService.isDarkTheme | async) ? color[200] : color[900]
|
||||
}"
|
||||
[ngClass]="{ active: active }"
|
||||
>
|
||||
<ng-container *ngIf="isMachine; else human">
|
||||
<i class="machine-icon las la-robot"></i>
|
||||
</ng-container>
|
||||
<ng-template #human>
|
||||
<span class="dontcloseonclick">{{ credentials }}</span>
|
||||
<img class="dontcloseonclick" *ngIf="avatarUrl" [src]="avatarUrl" (error)="errorHandler($event)" />
|
||||
</ng-template>
|
||||
</div>
|
||||
|
@ -52,4 +52,8 @@ export class AvatarComponent implements OnInit {
|
||||
const toGen = this.forColor || this.name || '';
|
||||
return getColorHash(toGen);
|
||||
}
|
||||
|
||||
public errorHandler(event: any) {
|
||||
(event.target as HTMLImageElement).style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
@ -12,22 +12,63 @@
|
||||
color="warn"
|
||||
(click)="removePolicy()"
|
||||
mat-stroked-button
|
||||
[disabled]="
|
||||
([
|
||||
serviceType === PolicyComponentServiceType.ADMIN
|
||||
? 'iam.policy.write'
|
||||
: serviceType === PolicyComponentServiceType.MGMT
|
||||
? 'policy.write'
|
||||
: ''
|
||||
]
|
||||
| hasRole
|
||||
| async) === false
|
||||
"
|
||||
>
|
||||
{{ 'POLICY.RESET' | translate }}
|
||||
</button>
|
||||
<!-- </ng-template> -->
|
||||
|
||||
<!-- [disabled]="(['domain.policy.write'] | hasRole | async) === false" -->
|
||||
<div class="content" *ngIf="domainData">
|
||||
<div class="row">
|
||||
<mat-checkbox color="primary" name="hasNumber" ngDefaultControl [(ngModel)]="domainData.userLoginMustBeDomain">
|
||||
<mat-checkbox
|
||||
color="primary"
|
||||
name="hasNumber"
|
||||
ngDefaultControl
|
||||
[(ngModel)]="domainData.userLoginMustBeDomain"
|
||||
[disabled]="
|
||||
([
|
||||
serviceType === PolicyComponentServiceType.ADMIN
|
||||
? 'iam.policy.write'
|
||||
: serviceType === PolicyComponentServiceType.MGMT
|
||||
? 'policy.write'
|
||||
: ''
|
||||
]
|
||||
| hasRole
|
||||
| async) === false
|
||||
"
|
||||
>
|
||||
{{ 'POLICY.DATA.USERLOGINMUSTBEDOMAIN' | translate }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
|
||||
<!-- [disabled]="(['domain.policy.write'] | hasRole | async) === false" -->
|
||||
<div class="row">
|
||||
<mat-checkbox color="primary" name="hasNumber" ngDefaultControl [(ngModel)]="domainData.validateOrgDomains">
|
||||
<mat-checkbox
|
||||
color="primary"
|
||||
name="hasNumber"
|
||||
ngDefaultControl
|
||||
[(ngModel)]="domainData.validateOrgDomains"
|
||||
[disabled]="
|
||||
([
|
||||
serviceType === PolicyComponentServiceType.ADMIN
|
||||
? 'iam.policy.write'
|
||||
: serviceType === PolicyComponentServiceType.MGMT
|
||||
? 'policy.write'
|
||||
: ''
|
||||
]
|
||||
| hasRole
|
||||
| async) === false
|
||||
"
|
||||
>
|
||||
{{ 'POLICY.DATA.VALIDATEORGDOMAINS' | translate }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
@ -38,15 +79,41 @@
|
||||
name="hasNumber"
|
||||
ngDefaultControl
|
||||
[(ngModel)]="domainData.smtpSenderAddressMatchesInstanceDomain"
|
||||
[disabled]="
|
||||
([
|
||||
serviceType === PolicyComponentServiceType.ADMIN
|
||||
? 'iam.policy.write'
|
||||
: serviceType === PolicyComponentServiceType.MGMT
|
||||
? 'policy.write'
|
||||
: ''
|
||||
]
|
||||
| hasRole
|
||||
| async) === false
|
||||
"
|
||||
>
|
||||
{{ 'POLICY.DATA.SMTPSENDERADDRESSMATCHESINSTANCEDOMAIN' | translate }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- [disabled]="(['domain.policy.write'] | hasRole | async) === false" -->
|
||||
<div class="btn-container">
|
||||
<button (click)="savePolicy()" color="primary" type="submit" mat-raised-button>
|
||||
<button
|
||||
(click)="savePolicy()"
|
||||
color="primary"
|
||||
type="submit"
|
||||
mat-raised-button
|
||||
[disabled]="
|
||||
([
|
||||
serviceType === PolicyComponentServiceType.ADMIN
|
||||
? 'iam.policy.write'
|
||||
: serviceType === PolicyComponentServiceType.MGMT
|
||||
? 'policy.write'
|
||||
: ''
|
||||
]
|
||||
| hasRole
|
||||
| async) === false
|
||||
"
|
||||
>
|
||||
{{ 'ACTIONS.SAVE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
|
@ -1,17 +1,27 @@
|
||||
<h2>{{ 'SETTING.DEFAULTLANGUAGE' | translate }}</h2>
|
||||
|
||||
<div class="spinner-wr">
|
||||
<mat-spinner diameter="30" *ngIf="loading" color="primary"></mat-spinner>
|
||||
</div>
|
||||
<h2>{{ 'SETTING.DEFAULTLANGUAGE' | translate }}</h2>
|
||||
|
||||
<cnsl-form-field class="default-language" label="Default Language" required="true">
|
||||
<cnsl-label>{{ 'SETTING.DEFAULTLANGUAGE' | translate }}</cnsl-label>
|
||||
<mat-select [(ngModel)]="defaultLanguage">
|
||||
<mat-select [(ngModel)]="defaultLanguage" [disabled]="(['iam.policy.write'] | hasRole | async) === false">
|
||||
<mat-option *ngFor="let lang of defaultLanguageOptions" [value]="lang">
|
||||
{{ lang }} - {{ 'SETTING.LANGUAGE.' + lang | translate }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
|
||||
<div class="general-btn-container">
|
||||
<button class="save-button" (click)="savePolicy()" color="primary" type="submit" mat-raised-button>
|
||||
<button
|
||||
class="save-button"
|
||||
(click)="savePolicy()"
|
||||
color="primary"
|
||||
type="submit"
|
||||
mat-raised-button
|
||||
[disabled]="(['iam.policy.write'] | hasRole | async) === false"
|
||||
>
|
||||
{{ 'ACTIONS.SAVE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
|
@ -5,6 +5,7 @@ import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||
import { MatSelectModule } from '@angular/material/select';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module';
|
||||
|
||||
import { CardModule } from '../../card/card.module';
|
||||
import { FormFieldModule } from '../../form-field/form-field.module';
|
||||
@ -20,6 +21,7 @@ import { GeneralSettingsComponent } from './general-settings.component';
|
||||
FormFieldModule,
|
||||
MatProgressSpinnerModule,
|
||||
MatSelectModule,
|
||||
HasRolePipeModule,
|
||||
TranslateModule,
|
||||
],
|
||||
exports: [GeneralSettingsComponent],
|
||||
|
@ -0,0 +1,29 @@
|
||||
<h1 mat-dialog-title class="title">
|
||||
<span>{{ data.title | translate }}</span>
|
||||
</h1>
|
||||
<div mat-dialog-content>
|
||||
<p class="desc cnsl-secondary-text">{{ data.desc | translate }}</p>
|
||||
|
||||
<cnsl-form-field class="form-field" label="Access Code" required="true">
|
||||
<cnsl-label>{{ 'MFA.TYPE' | translate }}</cnsl-label>
|
||||
<mat-select [(ngModel)]="newMfaType">
|
||||
<mat-option *ngFor="let mfa of availableMfaTypes" [value]="mfa">
|
||||
{{
|
||||
(data.componentType === LoginMethodComponentType.SecondFactor
|
||||
? 'MFA.SECONDFACTORTYPES.'
|
||||
: LoginMethodComponentType.MultiFactor
|
||||
? 'MFA.MULTIFACTORTYPES.'
|
||||
: '') + mfa | translate
|
||||
}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
<div mat-dialog-actions class="action">
|
||||
<button mat-stroked-button (click)="closeDialog()">
|
||||
<span>{{ 'ACTIONS.CLOSE' | translate }}</span>
|
||||
</button>
|
||||
<button [disabled]="false" mat-raised-button class="ok-button" color="primary" (click)="closeDialogWithCode()">
|
||||
<span>{{ 'ACTIONS.OK' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
@ -16,8 +16,8 @@ export class DialogAddTypeComponent {
|
||||
public LoginMethodComponentType: any = LoginMethodComponentType;
|
||||
public availableMfaTypes: Array<MultiFactorType | SecondFactorType> = [];
|
||||
public newMfaType!: MultiFactorType | SecondFactorType;
|
||||
constructor(public dialogRef: MatDialogRef<DialogAddTypeComponent>,
|
||||
@Inject(MAT_DIALOG_DATA) public data: any) {
|
||||
|
||||
constructor(public dialogRef: MatDialogRef<DialogAddTypeComponent>, @Inject(MAT_DIALOG_DATA) public data: any) {
|
||||
this.availableMfaTypes = data.types;
|
||||
}
|
||||
|
@ -0,0 +1,24 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { FactorTableComponent } from './factor-table.component';
|
||||
|
||||
describe('FactorTableComponent', () => {
|
||||
let component: FactorTableComponent;
|
||||
let fixture: ComponentFixture<FactorTableComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [FactorTableComponent],
|
||||
}).compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(FactorTableComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -6,16 +6,16 @@ import { BehaviorSubject, Observable } from 'rxjs';
|
||||
import { PolicyComponentServiceType } from 'src/app/modules/policies/policy-component-types.enum';
|
||||
import { WarnDialogComponent } from 'src/app/modules/warn-dialog/warn-dialog.component';
|
||||
import {
|
||||
AddMultiFactorToLoginPolicyRequest as AdminAddMultiFactorToLoginPolicyRequest,
|
||||
AddSecondFactorToLoginPolicyRequest as AdminAddSecondFactorToLoginPolicyRequest,
|
||||
RemoveMultiFactorFromLoginPolicyRequest as AdminRemoveMultiFactorFromLoginPolicyRequest,
|
||||
RemoveSecondFactorFromLoginPolicyRequest as AdminRemoveSecondFactorFromLoginPolicyRequest,
|
||||
AddMultiFactorToLoginPolicyRequest as AdminAddMultiFactorToLoginPolicyRequest,
|
||||
AddSecondFactorToLoginPolicyRequest as AdminAddSecondFactorToLoginPolicyRequest,
|
||||
RemoveMultiFactorFromLoginPolicyRequest as AdminRemoveMultiFactorFromLoginPolicyRequest,
|
||||
RemoveSecondFactorFromLoginPolicyRequest as AdminRemoveSecondFactorFromLoginPolicyRequest,
|
||||
} from 'src/app/proto/generated/zitadel/admin_pb';
|
||||
import {
|
||||
AddMultiFactorToLoginPolicyRequest as MgmtAddMultiFactorToLoginPolicyRequest,
|
||||
AddSecondFactorToLoginPolicyRequest as MgmtAddSecondFactorToLoginPolicyRequest,
|
||||
RemoveMultiFactorFromLoginPolicyRequest as MgmtRemoveMultiFactorFromLoginPolicyRequest,
|
||||
RemoveSecondFactorFromLoginPolicyRequest as MgmtRemoveSecondFactorFromLoginPolicyRequest,
|
||||
AddMultiFactorToLoginPolicyRequest as MgmtAddMultiFactorToLoginPolicyRequest,
|
||||
AddSecondFactorToLoginPolicyRequest as MgmtAddSecondFactorToLoginPolicyRequest,
|
||||
RemoveMultiFactorFromLoginPolicyRequest as MgmtRemoveMultiFactorFromLoginPolicyRequest,
|
||||
RemoveSecondFactorFromLoginPolicyRequest as MgmtRemoveSecondFactorFromLoginPolicyRequest,
|
||||
} from 'src/app/proto/generated/zitadel/management_pb';
|
||||
import { MultiFactorType, SecondFactorType } from 'src/app/proto/generated/zitadel/policy_pb';
|
||||
import { AdminService } from 'src/app/services/admin.service';
|
||||
@ -30,11 +30,11 @@ export enum LoginMethodComponentType {
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-mfa-table',
|
||||
templateUrl: './mfa-table.component.html',
|
||||
styleUrls: ['./mfa-table.component.scss'],
|
||||
selector: 'cnsl-factor-table',
|
||||
templateUrl: './factor-table.component.html',
|
||||
styleUrls: ['./factor-table.component.scss'],
|
||||
})
|
||||
export class MfaTableComponent implements OnInit {
|
||||
export class FactorTableComponent implements OnInit {
|
||||
public LoginMethodComponentType: any = LoginMethodComponentType;
|
||||
@Input() componentType!: LoginMethodComponentType;
|
||||
@Input() public serviceType!: PolicyComponentServiceType;
|
||||
@ -48,7 +48,7 @@ export class MfaTableComponent implements OnInit {
|
||||
|
||||
public PolicyComponentServiceType: any = PolicyComponentServiceType;
|
||||
|
||||
constructor(public translate: TranslateService, private toast: ToastService, private dialog: MatDialog) { }
|
||||
constructor(public translate: TranslateService, private toast: ToastService, private dialog: MatDialog) {}
|
||||
|
||||
public ngOnInit(): void {
|
||||
this.getData();
|
||||
@ -65,7 +65,7 @@ export class MfaTableComponent implements OnInit {
|
||||
width: '400px',
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe(resp => {
|
||||
dialogRef.afterClosed().subscribe((resp) => {
|
||||
if (resp) {
|
||||
if (this.serviceType === PolicyComponentServiceType.MGMT) {
|
||||
if (this.componentType === LoginMethodComponentType.MultiFactor) {
|
||||
@ -105,7 +105,6 @@ export class MfaTableComponent implements OnInit {
|
||||
}
|
||||
|
||||
public addMfa(): void {
|
||||
|
||||
let selection: any[] = [];
|
||||
|
||||
if (this.componentType === LoginMethodComponentType.MultiFactor) {
|
||||
@ -114,8 +113,8 @@ export class MfaTableComponent implements OnInit {
|
||||
selection = [SecondFactorType.SECOND_FACTOR_TYPE_U2F, SecondFactorType.SECOND_FACTOR_TYPE_OTP];
|
||||
}
|
||||
|
||||
this.mfas.forEach(mfa => {
|
||||
const index = selection.findIndex(sel => sel === mfa);
|
||||
this.mfas.forEach((mfa) => {
|
||||
const index = selection.findIndex((sel) => sel === mfa);
|
||||
if (index > -1) {
|
||||
selection.splice(index, 1);
|
||||
}
|
||||
@ -137,37 +136,49 @@ export class MfaTableComponent implements OnInit {
|
||||
if (this.componentType === LoginMethodComponentType.MultiFactor) {
|
||||
const req = new MgmtAddMultiFactorToLoginPolicyRequest();
|
||||
req.setType(mfaType as MultiFactorType);
|
||||
(this.service as ManagementService).addMultiFactorToLoginPolicy(req).then(() => {
|
||||
this.refreshPageAfterTimout(2000);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
(this.service as ManagementService)
|
||||
.addMultiFactorToLoginPolicy(req)
|
||||
.then(() => {
|
||||
this.refreshPageAfterTimout(2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
} else if (this.componentType === LoginMethodComponentType.SecondFactor) {
|
||||
const req = new MgmtAddSecondFactorToLoginPolicyRequest();
|
||||
req.setType(mfaType as SecondFactorType);
|
||||
(this.service as ManagementService).addSecondFactorToLoginPolicy(req).then(() => {
|
||||
this.refreshPageAfterTimout(2000);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
(this.service as ManagementService)
|
||||
.addSecondFactorToLoginPolicy(req)
|
||||
.then(() => {
|
||||
this.refreshPageAfterTimout(2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
} else if (this.serviceType === PolicyComponentServiceType.ADMIN) {
|
||||
if (this.componentType === LoginMethodComponentType.MultiFactor) {
|
||||
const req = new AdminAddMultiFactorToLoginPolicyRequest();
|
||||
req.setType(mfaType as MultiFactorType);
|
||||
(this.service as AdminService).addMultiFactorToLoginPolicy(req).then(() => {
|
||||
this.refreshPageAfterTimout(2000);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
(this.service as AdminService)
|
||||
.addMultiFactorToLoginPolicy(req)
|
||||
.then(() => {
|
||||
this.refreshPageAfterTimout(2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
} else if (this.componentType === LoginMethodComponentType.SecondFactor) {
|
||||
const req = new AdminAddSecondFactorToLoginPolicyRequest();
|
||||
req.setType(mfaType as SecondFactorType);
|
||||
(this.service as AdminService).addSecondFactorToLoginPolicy(req).then(() => {
|
||||
this.refreshPageAfterTimout(2000);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
(this.service as AdminService)
|
||||
.addSecondFactorToLoginPolicy(req)
|
||||
.then(() => {
|
||||
this.refreshPageAfterTimout(2000);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -179,39 +190,51 @@ export class MfaTableComponent implements OnInit {
|
||||
|
||||
if (this.serviceType === PolicyComponentServiceType.MGMT) {
|
||||
if (this.componentType === LoginMethodComponentType.MultiFactor) {
|
||||
(this.service as ManagementService).listLoginPolicyMultiFactors().then(resp => {
|
||||
this.mfas = resp.resultList;
|
||||
this.loadingSubject.next(false);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
this.loadingSubject.next(false);
|
||||
});
|
||||
(this.service as ManagementService)
|
||||
.listLoginPolicyMultiFactors()
|
||||
.then((resp) => {
|
||||
this.mfas = resp.resultList;
|
||||
this.loadingSubject.next(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
this.loadingSubject.next(false);
|
||||
});
|
||||
} else if (this.componentType === LoginMethodComponentType.SecondFactor) {
|
||||
(this.service as ManagementService).listLoginPolicySecondFactors().then(resp => {
|
||||
this.mfas = resp.resultList;
|
||||
this.loadingSubject.next(false);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
this.loadingSubject.next(false);
|
||||
});
|
||||
(this.service as ManagementService)
|
||||
.listLoginPolicySecondFactors()
|
||||
.then((resp) => {
|
||||
this.mfas = resp.resultList;
|
||||
this.loadingSubject.next(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
this.loadingSubject.next(false);
|
||||
});
|
||||
}
|
||||
} else if (this.serviceType === PolicyComponentServiceType.ADMIN) {
|
||||
if (this.componentType === LoginMethodComponentType.MultiFactor) {
|
||||
(this.service as AdminService).listLoginPolicyMultiFactors().then(resp => {
|
||||
this.mfas = resp.resultList;
|
||||
this.loadingSubject.next(false);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
this.loadingSubject.next(false);
|
||||
});
|
||||
(this.service as AdminService)
|
||||
.listLoginPolicyMultiFactors()
|
||||
.then((resp) => {
|
||||
this.mfas = resp.resultList;
|
||||
this.loadingSubject.next(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
this.loadingSubject.next(false);
|
||||
});
|
||||
} else if (this.componentType === LoginMethodComponentType.SecondFactor) {
|
||||
(this.service as AdminService).listLoginPolicySecondFactors().then(resp => {
|
||||
this.mfas = resp.resultList;
|
||||
this.loadingSubject.next(false);
|
||||
}).catch(error => {
|
||||
this.toast.showError(error);
|
||||
this.loadingSubject.next(false);
|
||||
});
|
||||
(this.service as AdminService)
|
||||
.listLoginPolicySecondFactors()
|
||||
.then((resp) => {
|
||||
this.mfas = resp.resultList;
|
||||
this.loadingSubject.next(false);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.toast.showError(error);
|
||||
this.loadingSubject.next(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -29,7 +29,20 @@
|
||||
<div class="login-policy-row" *ngIf="loginData">
|
||||
<cnsl-form-field class="passwordless-allowed" label="Access Code" required="true">
|
||||
<cnsl-label>{{ 'LOGINPOLICY.PASSWORDLESS' | translate }}</cnsl-label>
|
||||
<mat-select [(ngModel)]="loginData.passwordlessType">
|
||||
<mat-select
|
||||
[(ngModel)]="loginData.passwordlessType"
|
||||
[disabled]="
|
||||
([
|
||||
serviceType === PolicyComponentServiceType.ADMIN
|
||||
? 'iam.policy.write'
|
||||
: serviceType === PolicyComponentServiceType.MGMT
|
||||
? 'policy.write'
|
||||
: ''
|
||||
]
|
||||
| hasRole
|
||||
| async) === false
|
||||
"
|
||||
>
|
||||
<mat-option *ngFor="let pt of passwordlessTypes" [value]="pt">
|
||||
{{ 'LOGINPOLICY.PASSWORDLESSTYPE.' + pt | translate }}
|
||||
</mat-option>
|
||||
@ -38,7 +51,7 @@
|
||||
</div>
|
||||
|
||||
<cnsl-card class="max-card-width">
|
||||
<cnsl-mfa-table
|
||||
<cnsl-factor-table
|
||||
[service]="service"
|
||||
[serviceType]="serviceType"
|
||||
[componentType]="LoginMethodComponentType.MultiFactor"
|
||||
@ -55,7 +68,7 @@
|
||||
| async) === false
|
||||
"
|
||||
>
|
||||
</cnsl-mfa-table>
|
||||
</cnsl-factor-table>
|
||||
</cnsl-card>
|
||||
|
||||
<br />
|
||||
@ -64,12 +77,29 @@
|
||||
<p class="cnsl-secondary-text">{{ 'MFA.LIST.SECONDFACTORDESCRIPTION' | translate }}</p>
|
||||
|
||||
<div *ngIf="loginData" class="login-policy-row">
|
||||
<mat-checkbox card-actions class="login-policy-toggle" color="primary" ngDefaultControl [(ngModel)]="loginData.forceMfa">
|
||||
<mat-checkbox
|
||||
card-actions
|
||||
class="login-policy-toggle"
|
||||
color="primary"
|
||||
ngDefaultControl
|
||||
[(ngModel)]="loginData.forceMfa"
|
||||
[disabled]="
|
||||
([
|
||||
serviceType === PolicyComponentServiceType.ADMIN
|
||||
? 'iam.policy.write'
|
||||
: serviceType === PolicyComponentServiceType.MGMT
|
||||
? 'policy.write'
|
||||
: ''
|
||||
]
|
||||
| hasRole
|
||||
| async) === false
|
||||
"
|
||||
>
|
||||
{{ 'POLICY.DATA.FORCEMFA' | translate }}
|
||||
</mat-checkbox>
|
||||
</div>
|
||||
<cnsl-card class="max-card-width">
|
||||
<cnsl-mfa-table
|
||||
<cnsl-factor-table
|
||||
[service]="service"
|
||||
[serviceType]="serviceType"
|
||||
[componentType]="LoginMethodComponentType.SecondFactor"
|
||||
@ -85,7 +115,7 @@
|
||||
| async) === false
|
||||
"
|
||||
>
|
||||
</cnsl-mfa-table>
|
||||
</cnsl-factor-table>
|
||||
</cnsl-card>
|
||||
|
||||
<br />
|
||||
@ -149,6 +179,17 @@
|
||||
matTooltip="{{ 'POLICY.DATA.FORCEMFA_DESC' | translate }}"
|
||||
ngDefaultControl
|
||||
[(ngModel)]="loginData.allowUsernamePassword"
|
||||
[disabled]="
|
||||
([
|
||||
serviceType === PolicyComponentServiceType.ADMIN
|
||||
? 'iam.policy.write'
|
||||
: serviceType === PolicyComponentServiceType.MGMT
|
||||
? 'policy.write'
|
||||
: ''
|
||||
]
|
||||
| hasRole
|
||||
| async) === false
|
||||
"
|
||||
>
|
||||
{{ 'POLICY.DATA.ALLOWUSERNAMEPASSWORD' | translate }}
|
||||
</mat-checkbox>
|
||||
@ -158,7 +199,23 @@
|
||||
</cnsl-info-section> -->
|
||||
</div>
|
||||
<div class="login-policy-row">
|
||||
<mat-checkbox class="login-policy-toggle" color="primary" ngDefaultControl [(ngModel)]="loginData.allowRegister">
|
||||
<mat-checkbox
|
||||
class="login-policy-toggle"
|
||||
color="primary"
|
||||
ngDefaultControl
|
||||
[(ngModel)]="loginData.allowRegister"
|
||||
[disabled]="
|
||||
([
|
||||
serviceType === PolicyComponentServiceType.ADMIN
|
||||
? 'iam.policy.write'
|
||||
: serviceType === PolicyComponentServiceType.MGMT
|
||||
? 'policy.write'
|
||||
: ''
|
||||
]
|
||||
| hasRole
|
||||
| async) === false
|
||||
"
|
||||
>
|
||||
{{ 'POLICY.DATA.ALLOWREGISTER' | translate }}
|
||||
</mat-checkbox>
|
||||
|
||||
@ -169,7 +226,23 @@
|
||||
</ng-template> -->
|
||||
</div>
|
||||
<div class="login-policy-row">
|
||||
<mat-checkbox class="login-policy-toggle" color="primary" ngDefaultControl [(ngModel)]="loginData.allowExternalIdp">
|
||||
<mat-checkbox
|
||||
class="login-policy-toggle"
|
||||
color="primary"
|
||||
ngDefaultControl
|
||||
[(ngModel)]="loginData.allowExternalIdp"
|
||||
[disabled]="
|
||||
([
|
||||
serviceType === PolicyComponentServiceType.ADMIN
|
||||
? 'iam.policy.write'
|
||||
: serviceType === PolicyComponentServiceType.MGMT
|
||||
? 'policy.write'
|
||||
: ''
|
||||
]
|
||||
| hasRole
|
||||
| async) === false
|
||||
"
|
||||
>
|
||||
{{ 'POLICY.DATA.ALLOWEXTERNALIDP' | translate }}
|
||||
</mat-checkbox>
|
||||
|
||||
@ -181,7 +254,23 @@
|
||||
</div>
|
||||
|
||||
<div class="login-policy-row">
|
||||
<mat-checkbox class="login-policy-toggle" color="primary" ngDefaultControl [(ngModel)]="loginData.hidePasswordReset">
|
||||
<mat-checkbox
|
||||
class="login-policy-toggle"
|
||||
color="primary"
|
||||
ngDefaultControl
|
||||
[(ngModel)]="loginData.hidePasswordReset"
|
||||
[disabled]="
|
||||
([
|
||||
serviceType === PolicyComponentServiceType.ADMIN
|
||||
? 'iam.policy.write'
|
||||
: serviceType === PolicyComponentServiceType.MGMT
|
||||
? 'policy.write'
|
||||
: ''
|
||||
]
|
||||
| hasRole
|
||||
| async) === false
|
||||
"
|
||||
>
|
||||
{{ 'POLICY.DATA.HIDEPASSWORDRESET' | translate }}
|
||||
</mat-checkbox>
|
||||
|
||||
@ -198,6 +287,17 @@
|
||||
color="primary"
|
||||
ngDefaultControl
|
||||
[(ngModel)]="loginData.ignoreUnknownUsernames"
|
||||
[disabled]="
|
||||
([
|
||||
serviceType === PolicyComponentServiceType.ADMIN
|
||||
? 'iam.policy.write'
|
||||
: serviceType === PolicyComponentServiceType.MGMT
|
||||
? 'policy.write'
|
||||
: ''
|
||||
]
|
||||
| hasRole
|
||||
| async) === false
|
||||
"
|
||||
>
|
||||
{{ 'POLICY.DATA.IGNOREUNKNOWNUSERNAMES' | translate }}
|
||||
</mat-checkbox>
|
||||
@ -206,7 +306,22 @@
|
||||
<div class="login-policy-row">
|
||||
<cnsl-form-field class="form-field" label="Access Code" required="true">
|
||||
<cnsl-label>{{ 'POLICY.DATA.DEFAULTREDIRECTURI' | translate }}</cnsl-label>
|
||||
<input cnslInput placeholder="https://" [(ngModel)]="loginData.defaultRedirectUri" />
|
||||
<input
|
||||
cnslInput
|
||||
placeholder="https://"
|
||||
[(ngModel)]="loginData.defaultRedirectUri"
|
||||
[disabled]="
|
||||
([
|
||||
serviceType === PolicyComponentServiceType.ADMIN
|
||||
? 'iam.policy.write'
|
||||
: serviceType === PolicyComponentServiceType.MGMT
|
||||
? 'policy.write'
|
||||
: ''
|
||||
]
|
||||
| hasRole
|
||||
| async) === false
|
||||
"
|
||||
/>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
</div>
|
||||
@ -214,7 +329,24 @@
|
||||
<br />
|
||||
|
||||
<div class="login-policy-btn-container">
|
||||
<button class="login-policy-save-button" (click)="savePolicy()" color="primary" type="submit" mat-raised-button>
|
||||
<button
|
||||
class="login-policy-save-button"
|
||||
(click)="savePolicy()"
|
||||
color="primary"
|
||||
type="submit"
|
||||
mat-raised-button
|
||||
[disabled]="
|
||||
([
|
||||
serviceType === PolicyComponentServiceType.ADMIN
|
||||
? 'iam.policy.write'
|
||||
: serviceType === PolicyComponentServiceType.MGMT
|
||||
? 'policy.write'
|
||||
: ''
|
||||
]
|
||||
| hasRole
|
||||
| async) === false
|
||||
"
|
||||
>
|
||||
{{ 'ACTIONS.SAVE' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { Component, Injector, Input, OnInit, Type } from '@angular/core';
|
||||
import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms';
|
||||
import { Duration } from 'google-protobuf/google/protobuf/duration_pb';
|
||||
import { take } from 'rxjs';
|
||||
import {
|
||||
GetLoginPolicyResponse as AdminGetLoginPolicyResponse,
|
||||
UpdateLoginPolicyRequest,
|
||||
@ -12,12 +13,13 @@ import {
|
||||
} from 'src/app/proto/generated/zitadel/management_pb';
|
||||
import { LoginPolicy, PasswordlessType } from 'src/app/proto/generated/zitadel/policy_pb';
|
||||
import { AdminService } from 'src/app/services/admin.service';
|
||||
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
import { InfoSectionType } from '../../info-section/info-section.component';
|
||||
import { PolicyComponentServiceType } from '../policy-component-types.enum';
|
||||
import { LoginMethodComponentType } from './mfa-table/mfa-table.component';
|
||||
import { LoginMethodComponentType } from './factor-table/factor-table.component';
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-login-policy',
|
||||
@ -40,21 +42,24 @@ export class LoginPolicyComponent implements OnInit {
|
||||
public InfoSectionType: any = InfoSectionType;
|
||||
public PasswordlessType: any = PasswordlessType;
|
||||
public lifetimeForm!: FormGroup;
|
||||
constructor(private toast: ToastService, private injector: Injector, private fb: FormBuilder) {
|
||||
constructor(
|
||||
private toast: ToastService,
|
||||
private injector: Injector,
|
||||
private fb: FormBuilder,
|
||||
private authService: GrpcAuthService,
|
||||
) {
|
||||
this.lifetimeForm = this.fb.group({
|
||||
passwordCheckLifetime: [240, [Validators.required]],
|
||||
externalLoginCheckLifetime: [12, [Validators.required]],
|
||||
mfaInitSkipLifetime: [720, [Validators.required]],
|
||||
secondFactorCheckLifetime: [12, [Validators.required]],
|
||||
multiFactorCheckLifetime: [12, [Validators.required]],
|
||||
passwordCheckLifetime: [{ disabled: true, value: 240 }, [Validators.required]],
|
||||
externalLoginCheckLifetime: [{ disabled: true, value: 12 }, [Validators.required]],
|
||||
mfaInitSkipLifetime: [{ disabled: true, value: 720 }, [Validators.required]],
|
||||
secondFactorCheckLifetime: [{ disabled: true, value: 12 }, [Validators.required]],
|
||||
multiFactorCheckLifetime: [{ disabled: true, value: 12 }, [Validators.required]],
|
||||
});
|
||||
}
|
||||
|
||||
private fetchData(): void {
|
||||
this.getData()
|
||||
.then((resp) => {
|
||||
console.log(resp);
|
||||
|
||||
if (resp.policy) {
|
||||
this.loginData = resp.policy;
|
||||
this.loading = false;
|
||||
@ -107,6 +112,21 @@ export class LoginPolicyComponent implements OnInit {
|
||||
break;
|
||||
}
|
||||
this.fetchData();
|
||||
this.authService
|
||||
.isAllowed(
|
||||
this.serviceType === PolicyComponentServiceType.ADMIN
|
||||
? ['iam.policy.write']
|
||||
: this.serviceType === PolicyComponentServiceType.MGMT
|
||||
? ['policy.write']
|
||||
: [],
|
||||
)
|
||||
.pipe(take(1))
|
||||
.subscribe((allowed) => {
|
||||
console.log(allowed);
|
||||
if (allowed) {
|
||||
this.lifetimeForm.enable();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private async getData(): Promise<AdminGetLoginPolicyResponse.AsObject | MgmtGetLoginPolicyResponse.AsObject> {
|
||||
|
@ -18,13 +18,13 @@ import { InputModule } from 'src/app/modules/input/input.module';
|
||||
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module';
|
||||
|
||||
import { InfoSectionModule } from '../../info-section/info-section.module';
|
||||
import { DialogAddTypeComponent } from './factor-table/dialog-add-type/dialog-add-type.component';
|
||||
import { FactorTableComponent } from './factor-table/factor-table.component';
|
||||
import { LoginPolicyRoutingModule } from './login-policy-routing.module';
|
||||
import { LoginPolicyComponent } from './login-policy.component';
|
||||
import { DialogAddTypeComponent } from './mfa-table/dialog-add-type/dialog-add-type.component';
|
||||
import { MfaTableComponent } from './mfa-table/mfa-table.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [LoginPolicyComponent, MfaTableComponent, DialogAddTypeComponent],
|
||||
declarations: [LoginPolicyComponent, FactorTableComponent, DialogAddTypeComponent],
|
||||
imports: [
|
||||
LoginPolicyRoutingModule,
|
||||
CommonModule,
|
||||
|
@ -1,20 +0,0 @@
|
||||
<h1 mat-dialog-title class="title"><span>{{data.title | translate}}</span></h1>
|
||||
<div mat-dialog-content>
|
||||
<p class="desc cnsl-secondary-text">{{data.desc | translate}}</p>
|
||||
|
||||
<cnsl-form-field class="form-field" label="Access Code" required="true">
|
||||
<cnsl-label>{{'MFA.TYPE' | translate}}</cnsl-label>
|
||||
<mat-select [(ngModel)]="newMfaType">
|
||||
<mat-option *ngFor="let mfa of availableMfaTypes" [value]="mfa">
|
||||
{{(data.componentType === LoginMethodComponentType.SecondFactor ? 'MFA.SECONDFACTORTYPES.':
|
||||
LoginMethodComponentType.MultiFactor ? 'MFA.MULTIFACTORTYPES.': '')+mfa | translate}}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</cnsl-form-field>
|
||||
</div>
|
||||
<div mat-dialog-actions class="action">
|
||||
<button mat-stroked-button (click)="closeDialog()"><span>{{'ACTIONS.CLOSE' | translate}}</span></button>
|
||||
<button [disabled]="false" mat-raised-button class="ok-button" color="primary"
|
||||
(click)="closeDialogWithCode()"><span>{{'ACTIONS.OK' | translate}}</span>
|
||||
</button>
|
||||
</div>
|
@ -1,25 +0,0 @@
|
||||
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
|
||||
|
||||
import { MfaTableComponent } from './mfa-table.component';
|
||||
|
||||
describe('MfaTableComponent', () => {
|
||||
let component: MfaTableComponent;
|
||||
let fixture: ComponentFixture<MfaTableComponent>;
|
||||
|
||||
beforeEach(waitForAsync(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [MfaTableComponent],
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(MfaTableComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
@ -1,5 +1,10 @@
|
||||
<h2>{{ 'POLICY.LOGIN_TEXTS.TITLE' | translate }}</h2>
|
||||
<p class="cnsl-secondary-text">{{ 'POLICY.LOGIN_TEXTS.DESCRIPTION' | translate }}</p>
|
||||
|
||||
<div *ngIf="loading" class="spinner-wr">
|
||||
<mat-spinner diameter="30" color="primary"></mat-spinner>
|
||||
</div>
|
||||
|
||||
<div class="date">
|
||||
<div>
|
||||
<p class="newer-title" *ngIf="newerVersionExists">{{ 'POLICY.LOGIN_TEXTS.NEWERVERSIONEXISTS' | translate }}</p>
|
||||
|
@ -93,6 +93,7 @@ const REQUESTMAP = {
|
||||
styleUrls: ['./login-texts.component.scss'],
|
||||
})
|
||||
export class LoginTextsComponent implements OnInit, OnDestroy {
|
||||
public loading: boolean = false;
|
||||
public currentPolicyChangeDate!: Timestamp.AsObject | undefined;
|
||||
public newerPolicyChangeDate!: Timestamp.AsObject | undefined;
|
||||
|
||||
@ -208,6 +209,7 @@ export class LoginTextsComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
public async loadData(): Promise<any> {
|
||||
this.loading = true;
|
||||
const reqDefaultInit = REQUESTMAP[this.serviceType].getDefault;
|
||||
reqDefaultInit.setLanguage(this.locale);
|
||||
this.getDefaultInitMessageTextMap$ = from(this.getDefaultValues(reqDefaultInit)).pipe(map((m) => m[this.currentSubMap]));
|
||||
@ -215,12 +217,14 @@ export class LoginTextsComponent implements OnInit, OnDestroy {
|
||||
const reqCustomInit = REQUESTMAP[this.serviceType].get.setLanguage(this.locale);
|
||||
return this.getCurrentValues(reqCustomInit)
|
||||
.then((policy) => {
|
||||
this.loading = false;
|
||||
if (policy) {
|
||||
this.totalCustomPolicy = policy;
|
||||
this.getCustomInitMessageTextMap$.next(policy[this.currentSubMap]);
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
this.loading = false;
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
|
@ -1,6 +1,10 @@
|
||||
<h2>{{ 'POLICY.MESSAGE_TEXTS.TITLE' | translate }}</h2>
|
||||
<p class="cnsl-secondary-text">{{ 'POLICY.MESSAGE_TEXTS.DESCRIPTION' | translate }}</p>
|
||||
|
||||
<div *ngIf="loading" class="spinner-wr">
|
||||
<mat-spinner diameter="30" color="primary"></mat-spinner>
|
||||
</div>
|
||||
|
||||
<div class="message-texts-top-actions">
|
||||
<cnsl-form-field class="type">
|
||||
<cnsl-label>{{ 'POLICY.MESSAGE_TEXTS.TYPE' | translate }}</cnsl-label>
|
||||
|
@ -37,7 +37,6 @@ import { MessageCustomText } from 'src/app/proto/generated/zitadel/text_pb';
|
||||
import { AdminService } from 'src/app/services/admin.service';
|
||||
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { StorageService } from 'src/app/services/storage.service';
|
||||
import { ToastService } from 'src/app/services/toast.service';
|
||||
|
||||
import { InfoSectionType } from '../../info-section/info-section.component';
|
||||
@ -275,6 +274,7 @@ const REQUESTMAP = {
|
||||
styleUrls: ['./message-texts.component.scss'],
|
||||
})
|
||||
export class MessageTextsComponent implements OnInit, OnDestroy {
|
||||
public loading: boolean = false;
|
||||
public getDefaultInitMessageTextMap$: Observable<{ [key: string]: string }> = of({});
|
||||
public getCustomInitMessageTextMap$: BehaviorSubject<{ [key: string]: string | boolean }> = new BehaviorSubject({}); // boolean because of isDefault
|
||||
|
||||
@ -400,7 +400,6 @@ export class MessageTextsComponent implements OnInit, OnDestroy {
|
||||
private toast: ToastService,
|
||||
private injector: Injector,
|
||||
private dialog: MatDialog,
|
||||
private storageService: StorageService,
|
||||
) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
@ -493,11 +492,14 @@ export class MessageTextsComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
const reqCustomInit = REQUESTMAP[this.serviceType][type].get.setLanguage(this.locale);
|
||||
this.loading = true;
|
||||
return this.getCurrentValues(type, reqCustomInit)
|
||||
?.then((data) => {
|
||||
this.loading = false;
|
||||
this.getCustomInitMessageTextMap$.next(data);
|
||||
})
|
||||
.catch((error) => {
|
||||
this.loading = false;
|
||||
this.toast.showError(error);
|
||||
});
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
<h2>{{ 'SETTING.SMTP.TITLE' | translate }}</h2>
|
||||
|
||||
<div class="spinner-wr">
|
||||
<mat-spinner diameter="30" *ngIf="smtpLoading || smsProvidersLoading" color="primary"></mat-spinner>
|
||||
</div>
|
||||
|
||||
<h2>{{ 'SETTING.SMTP.TITLE' | translate }}</h2>
|
||||
|
||||
<cnsl-info-section
|
||||
*ngIf="!smtpLoading && !form.valid"
|
||||
class="info-section-warn"
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
@include input-theme($theme);
|
||||
@include cnsl-label-theme($theme);
|
||||
@include mat.all-component-themes($theme);
|
||||
// @include mat.all-component-themes($theme);
|
||||
|
||||
$primary: map-get($theme, primary);
|
||||
$primary-color: mat.get-color-from-palette($primary, 500);
|
||||
|
@ -70,6 +70,17 @@
|
||||
mat-raised-button
|
||||
color="primary"
|
||||
(click)="activatePolicy()"
|
||||
[disabled]="
|
||||
([
|
||||
serviceType === PolicyComponentServiceType.ADMIN
|
||||
? 'iam.policy.write'
|
||||
: serviceType === PolicyComponentServiceType.MGMT
|
||||
? 'policy.write'
|
||||
: ''
|
||||
]
|
||||
| hasRole
|
||||
| async) === false
|
||||
"
|
||||
>
|
||||
{{ 'POLICY.PRIVATELABELING.ACTIVATEPREVIEW' | translate }}
|
||||
</button>
|
||||
@ -391,7 +402,18 @@
|
||||
class="toggle"
|
||||
color="primary"
|
||||
ngDefaultControl
|
||||
[disabled]="view === View.CURRENT"
|
||||
[disabled]="
|
||||
view === View.CURRENT ||
|
||||
([
|
||||
serviceType === PolicyComponentServiceType.ADMIN
|
||||
? 'iam.policy.write'
|
||||
: serviceType === PolicyComponentServiceType.MGMT
|
||||
? 'policy.write'
|
||||
: ''
|
||||
]
|
||||
| hasRole
|
||||
| async) === false
|
||||
"
|
||||
[(ngModel)]="view === View.CURRENT ? data.hideLoginNameSuffix : previewData.hideLoginNameSuffix"
|
||||
(change)="savePolicy()"
|
||||
>
|
||||
@ -402,9 +424,20 @@
|
||||
class="toggle"
|
||||
color="primary"
|
||||
ngDefaultControl
|
||||
[disabled]="view === View.CURRENT"
|
||||
[(ngModel)]="view === View.CURRENT ? data.disableWatermark : previewData.disableWatermark"
|
||||
(change)="savePolicy()"
|
||||
[disabled]="
|
||||
view === View.CURRENT ||
|
||||
([
|
||||
serviceType === PolicyComponentServiceType.ADMIN
|
||||
? 'iam.policy.write'
|
||||
: serviceType === PolicyComponentServiceType.MGMT
|
||||
? 'policy.write'
|
||||
: ''
|
||||
]
|
||||
| hasRole
|
||||
| async) === false
|
||||
"
|
||||
>
|
||||
{{ 'POLICY.DATA.DISABLEWATERMARK' | translate }}
|
||||
</mat-slide-toggle>
|
||||
|
@ -12,6 +12,7 @@ import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { ColorChromeModule } from 'ngx-color/chrome';
|
||||
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
|
||||
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module';
|
||||
|
||||
import { DropzoneModule } from '../../../directives/dropzone/dropzone.module';
|
||||
import { CardModule } from '../../card/card.module';
|
||||
@ -42,6 +43,7 @@ import { PrivateLabelingPolicyComponent } from './private-labeling-policy.compon
|
||||
TranslateModule,
|
||||
DetailLayoutModule,
|
||||
DropzoneModule,
|
||||
HasRolePipeModule,
|
||||
MatProgressSpinnerModule,
|
||||
MatExpansionModule,
|
||||
InfoSectionModule,
|
||||
|
@ -1,72 +1,125 @@
|
||||
import { PolicyComponentServiceType } from '../policies/policy-component-types.enum';
|
||||
import { SidenavSetting } from '../sidenav/sidenav.component';
|
||||
|
||||
export const GENERAL: SidenavSetting = {
|
||||
id: 'general',
|
||||
i18nKey: 'SETTINGS.LIST.GENERAL',
|
||||
requiredRoles: {
|
||||
[PolicyComponentServiceType.ADMIN]: ['iam.policy.read'],
|
||||
},
|
||||
};
|
||||
|
||||
export const OIDC: SidenavSetting = {
|
||||
id: 'oidc',
|
||||
i18nKey: 'SETTINGS.LIST.OIDC',
|
||||
requiredRoles: {
|
||||
[PolicyComponentServiceType.ADMIN]: ['iam.policy.read'],
|
||||
},
|
||||
};
|
||||
|
||||
export const SECRETS: SidenavSetting = {
|
||||
id: 'secrets',
|
||||
i18nKey: 'SETTINGS.LIST.SECRETS',
|
||||
requiredRoles: {
|
||||
[PolicyComponentServiceType.ADMIN]: ['iam.policy.read'],
|
||||
},
|
||||
};
|
||||
|
||||
export const LOGIN: SidenavSetting = {
|
||||
id: 'login',
|
||||
i18nKey: 'SETTINGS.LIST.LOGIN',
|
||||
groupI18nKey: 'SETTINGS.GROUPS.LOGIN',
|
||||
requiredRoles: {
|
||||
[PolicyComponentServiceType.MGMT]: ['policy.read'],
|
||||
[PolicyComponentServiceType.ADMIN]: ['iam.policy.read'],
|
||||
},
|
||||
};
|
||||
|
||||
export const DOMAIN: SidenavSetting = {
|
||||
id: 'domain',
|
||||
i18nKey: 'SETTINGS.LIST.DOMAIN',
|
||||
groupI18nKey: 'SETTINGS.GROUPS.DOMAIN',
|
||||
requiredRoles: {
|
||||
[PolicyComponentServiceType.MGMT]: ['policy.read'],
|
||||
[PolicyComponentServiceType.ADMIN]: ['iam.policy.read'],
|
||||
},
|
||||
};
|
||||
|
||||
export const LOCKOUT: SidenavSetting = {
|
||||
id: 'lockout',
|
||||
i18nKey: 'SETTINGS.LIST.LOCKOUT',
|
||||
groupI18nKey: 'SETTINGS.GROUPS.LOGIN',
|
||||
requiredRoles: {
|
||||
[PolicyComponentServiceType.MGMT]: ['policy.read'],
|
||||
[PolicyComponentServiceType.ADMIN]: ['iam.policy.read'],
|
||||
},
|
||||
};
|
||||
|
||||
export const COMPLEXITY: SidenavSetting = {
|
||||
id: 'complexity',
|
||||
i18nKey: 'SETTINGS.LIST.COMPLEXITY',
|
||||
groupI18nKey: 'SETTINGS.GROUPS.LOGIN',
|
||||
requiredRoles: {
|
||||
[PolicyComponentServiceType.MGMT]: ['policy.read'],
|
||||
[PolicyComponentServiceType.ADMIN]: ['iam.policy.read'],
|
||||
},
|
||||
};
|
||||
|
||||
export const IDP: SidenavSetting = { id: 'idp', i18nKey: 'SETTINGS.LIST.IDP', groupI18nKey: 'SETTINGS.GROUPS.LOGIN' };
|
||||
export const IDP: SidenavSetting = {
|
||||
id: 'idp',
|
||||
i18nKey: 'SETTINGS.LIST.IDP',
|
||||
groupI18nKey: 'SETTINGS.GROUPS.LOGIN',
|
||||
requiredRoles: {
|
||||
[PolicyComponentServiceType.MGMT]: ['policy.read'],
|
||||
[PolicyComponentServiceType.ADMIN]: ['iam.policy.read'],
|
||||
},
|
||||
};
|
||||
|
||||
export const NOTIFICATIONS: SidenavSetting = {
|
||||
id: 'notifications',
|
||||
i18nKey: 'SETTINGS.LIST.NOTIFICATIONS',
|
||||
groupI18nKey: 'SETTINGS.GROUPS.NOTIFICATIONS',
|
||||
requiredRoles: {
|
||||
[PolicyComponentServiceType.ADMIN]: ['iam.policy.read'],
|
||||
},
|
||||
};
|
||||
|
||||
export const MESSAGETEXTS: SidenavSetting = {
|
||||
id: 'messagetexts',
|
||||
i18nKey: 'SETTINGS.LIST.MESSAGETEXTS',
|
||||
groupI18nKey: 'SETTINGS.GROUPS.APPEARANCE',
|
||||
requiredRoles: {
|
||||
[PolicyComponentServiceType.MGMT]: ['policy.read'],
|
||||
[PolicyComponentServiceType.ADMIN]: ['iam.policy.read'],
|
||||
},
|
||||
};
|
||||
|
||||
export const LOGINTEXTS: SidenavSetting = {
|
||||
id: 'logintexts',
|
||||
i18nKey: 'SETTINGS.LIST.LOGINTEXTS',
|
||||
groupI18nKey: 'SETTINGS.GROUPS.APPEARANCE',
|
||||
requiredRoles: {
|
||||
[PolicyComponentServiceType.MGMT]: ['policy.read'],
|
||||
[PolicyComponentServiceType.ADMIN]: ['iam.policy.read'],
|
||||
},
|
||||
};
|
||||
|
||||
export const PRIVACYPOLICY: SidenavSetting = {
|
||||
id: 'privacypolicy',
|
||||
i18nKey: 'SETTINGS.LIST.PRIVACYPOLICY',
|
||||
groupI18nKey: 'SETTINGS.GROUPS.OTHER',
|
||||
requiredRoles: {
|
||||
[PolicyComponentServiceType.MGMT]: ['policy.read'],
|
||||
[PolicyComponentServiceType.ADMIN]: ['iam.policy.read'],
|
||||
},
|
||||
};
|
||||
|
||||
export const BRANDING: SidenavSetting = {
|
||||
id: 'branding',
|
||||
i18nKey: 'SETTINGS.LIST.BRANDING',
|
||||
groupI18nKey: 'SETTINGS.GROUPS.APPEARANCE',
|
||||
requiredRoles: {
|
||||
[PolicyComponentServiceType.MGMT]: ['policy.read'],
|
||||
[PolicyComponentServiceType.ADMIN]: ['iam.policy.read'],
|
||||
},
|
||||
};
|
||||
|
@ -28,6 +28,11 @@
|
||||
|
||||
<button
|
||||
(click)="value = setting.id"
|
||||
*ngIf="
|
||||
!setting.requiredRoles ||
|
||||
(setting.requiredRoles.mgmt && (setting.requiredRoles.mgmt | hasRole | async)) ||
|
||||
(setting.requiredRoles.admin && (setting.requiredRoles.admin | hasRole | async))
|
||||
"
|
||||
class="sidenav-setting-list-element hide-on-mobile"
|
||||
[ngClass]="{ active: currentSetting === setting.id, show: currentSetting === undefined }"
|
||||
>
|
||||
|
@ -8,7 +8,10 @@ export interface SidenavSetting {
|
||||
id: string;
|
||||
i18nKey: string;
|
||||
groupI18nKey?: string;
|
||||
requiredRoles?: { [serviceType in PolicyComponentServiceType]: string[] };
|
||||
requiredRoles?: {
|
||||
[PolicyComponentServiceType.MGMT]?: string[];
|
||||
[PolicyComponentServiceType.ADMIN]?: string[];
|
||||
};
|
||||
showWarn?: boolean;
|
||||
}
|
||||
|
||||
@ -26,6 +29,7 @@ export class SidenavComponent implements ControlValueAccessor, OnInit {
|
||||
@Input() public settingsList: SidenavSetting[] = [];
|
||||
@Input() public queryParam: string = '';
|
||||
|
||||
public PolicyComponentServiceType: any = PolicyComponentServiceType;
|
||||
constructor(private router: Router, private route: ActivatedRoute) {}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
@ -4,12 +4,13 @@ import { FormsModule } from '@angular/forms';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module';
|
||||
|
||||
import { SidenavComponent } from './sidenav.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [SidenavComponent],
|
||||
imports: [CommonModule, FormsModule, RouterModule, MatIconModule, TranslateModule],
|
||||
imports: [CommonModule, FormsModule, RouterModule, HasRolePipeModule, MatIconModule, TranslateModule],
|
||||
exports: [SidenavComponent],
|
||||
})
|
||||
export class SidenavModule {}
|
||||
|
@ -35,6 +35,7 @@
|
||||
(changedLanguage)="changedLanguage($event)"
|
||||
(changeUsernameClicked)="changeUsername()"
|
||||
(submitData)="saveProfile($event)"
|
||||
(avatarChanged)="refreshUser()"
|
||||
>
|
||||
</cnsl-detail-form>
|
||||
</cnsl-card>
|
||||
|
@ -38,13 +38,13 @@ export class AuthUserDetailComponent implements OnDestroy {
|
||||
public refreshChanges$: EventEmitter<void> = new EventEmitter();
|
||||
|
||||
public settingsList: SidenavSetting[] = [
|
||||
{ id: 'general', i18nKey: 'USER.SETTINGS.GENERAL'},
|
||||
{ id: 'idp', i18nKey: 'USER.SETTINGS.IDP'},
|
||||
{ id: 'passwordless', i18nKey: 'USER.SETTINGS.PASSWORDLESS'},
|
||||
{ id: 'mfa', i18nKey: 'USER.SETTINGS.MFA'},
|
||||
{ id: 'grants', i18nKey: 'USER.SETTINGS.USERGRANTS'},
|
||||
{ id: 'memberships', i18nKey: 'USER.SETTINGS.MEMBERSHIPS'},
|
||||
{ id: 'metadata', i18nKey: 'USER.SETTINGS.METADATA'},
|
||||
{ id: 'general', i18nKey: 'USER.SETTINGS.GENERAL' },
|
||||
{ id: 'idp', i18nKey: 'USER.SETTINGS.IDP' },
|
||||
{ id: 'passwordless', i18nKey: 'USER.SETTINGS.PASSWORDLESS' },
|
||||
{ id: 'mfa', i18nKey: 'USER.SETTINGS.MFA' },
|
||||
{ id: 'grants', i18nKey: 'USER.SETTINGS.USERGRANTS' },
|
||||
{ id: 'memberships', i18nKey: 'USER.SETTINGS.MEMBERSHIPS' },
|
||||
{ id: 'metadata', i18nKey: 'USER.SETTINGS.METADATA' },
|
||||
];
|
||||
public currentSetting: string | undefined = this.settingsList[0].id;
|
||||
|
||||
|
@ -22,6 +22,7 @@ export class DetailFormComponent implements OnDestroy, OnChanges {
|
||||
@Output() public submitData: EventEmitter<Profile.AsObject> = new EventEmitter<Profile.AsObject>();
|
||||
@Output() public changedLanguage: EventEmitter<string> = new EventEmitter<string>();
|
||||
@Output() public changeUsernameClicked: EventEmitter<void> = new EventEmitter();
|
||||
@Output() public avatarChanged: EventEmitter<void> = new EventEmitter();
|
||||
|
||||
public profileForm!: FormGroup;
|
||||
|
||||
@ -79,8 +80,9 @@ export class DetailFormComponent implements OnDestroy, OnChanges {
|
||||
width: '400px',
|
||||
});
|
||||
|
||||
dialogRef.afterClosed().subscribe((resp) => {
|
||||
if (resp) {
|
||||
dialogRef.afterClosed().subscribe((shouldReload) => {
|
||||
if (shouldReload) {
|
||||
this.avatarChanged.emit();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -53,6 +53,6 @@ export class ProfilePictureComponent {
|
||||
}
|
||||
|
||||
public closeDialog(): void {
|
||||
this.dialogRef.close(false);
|
||||
this.dialogRef.close(true);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Injectable } from '@angular/core';
|
||||
import { lastValueFrom } from 'rxjs';
|
||||
|
||||
import { PolicyComponentServiceType } from '../modules/policies/policy-component-types.enum';
|
||||
import { Theme } from '../modules/policies/private-labeling-policy/private-labeling-policy.component';
|
||||
@ -80,9 +81,7 @@ export class AssetService {
|
||||
}
|
||||
|
||||
private async getServiceUrl(): Promise<string> {
|
||||
const url = await this.http
|
||||
.get('./assets/environment.json')
|
||||
.toPromise()
|
||||
const url = await lastValueFrom(this.http.get('./assets/environment.json'))
|
||||
.then((data: any) => {
|
||||
if (data && data.api) {
|
||||
return data.api;
|
||||
|
@ -251,6 +251,19 @@ export class GrpcAuthService {
|
||||
.then((resp) => resp.toObject());
|
||||
}
|
||||
|
||||
public loadMyUser(): void {
|
||||
from(this.getMyUser())
|
||||
.pipe(
|
||||
map((resp) => resp.user),
|
||||
catchError((_) => {
|
||||
return of(undefined);
|
||||
}),
|
||||
)
|
||||
.subscribe((user) => {
|
||||
this.userSubject.next(user);
|
||||
});
|
||||
}
|
||||
|
||||
public getMyUser(): Promise<GetMyUserResponse.AsObject> {
|
||||
return this.grpcService.auth.getMyUser(new GetMyUserRequest(), null).then((resp) => resp.toObject());
|
||||
}
|
||||
|
@ -277,8 +277,8 @@
|
||||
"U2F_NAME": "Authentifikator Name",
|
||||
"TYPE": {
|
||||
"0": "Keine MFA definiert",
|
||||
"1": "OTP",
|
||||
"2": "U2F"
|
||||
"1": "One Time Password (OTP)",
|
||||
"2": "Fingerabdruck, Security Keys, Face ID und andere"
|
||||
},
|
||||
"STATE": {
|
||||
"0": "Kein Status",
|
||||
@ -324,16 +324,16 @@
|
||||
"OTP": "OTP (One-Time Password)",
|
||||
"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.",
|
||||
"U2F": "U2F (Universal 2nd Factor)",
|
||||
"U2F_DIALOG_TITLE": "U2F hinzufügen",
|
||||
"U2F_DIALOG_DESCRIPTION": "Gib einen Namen für den von dir verwendeten Universellen Multifaktor an.",
|
||||
"U2F_SUCCESS": "U2F erfolgreich erstellt!",
|
||||
"U2F": "Fingerabdruck, Security Key, Face ID oder andere",
|
||||
"U2F_DIALOG_TITLE": "Faktor hinzufügen",
|
||||
"U2F_DIALOG_DESCRIPTION": "Gib einen Namen für den von dir verwendeten Authentikator an.",
|
||||
"U2F_SUCCESS": "Faktor erfolgreich hinzugefügt!",
|
||||
"U2F_ERROR": "Ein Fehler ist aufgetreten!",
|
||||
"U2F_NAME": "U2F Name",
|
||||
"U2F_NAME": "Authenticator Name",
|
||||
"TYPE": {
|
||||
"0": "Keine MFA definiert",
|
||||
"1": "OTP",
|
||||
"2": "U2F"
|
||||
"2": "Fingerabdruck, Security Key, Face ID oder andere"
|
||||
},
|
||||
"STATE": {
|
||||
"0": "Kein Status",
|
||||
@ -558,7 +558,7 @@
|
||||
"PHONEVERIFICATIONSENT": "Bestätigungscode per Telefonnummer gesendet.",
|
||||
"EMAILVERIFICATIONSENT": "Bestätigungscode per E-Mail gesendet.",
|
||||
"OTPREMOVED": "OTP entfernt.",
|
||||
"U2FREMOVED": "U2F entfernt.",
|
||||
"U2FREMOVED": "Faktor entfernt.",
|
||||
"PASSWORDLESSREMOVED": "Passwortlos entfernt.",
|
||||
"INITIALPASSWORDSET": "Initiales Passwort gesetzt.",
|
||||
"PASSWORDNOTIFICATIONSENT": "Passwortänderung mittgeteilt.",
|
||||
@ -912,7 +912,7 @@
|
||||
},
|
||||
"PRIVATELABELING": {
|
||||
"TITLE": "Branding",
|
||||
"DESCRIPTION": "Verleihe dem Login deinen benutzerdefinierten Style und passe das Verhalten an.",
|
||||
"DESCRIPTION": "Verleihen Sie dem Login Ihren benutzerdefinierten Style und passen Sie das Verhalten an.",
|
||||
"PREVIEW_DESCRIPTION": "Änderungen dieser Richtlinie werden automatisch in der Preview Umgebung verfügbar.",
|
||||
"BTN": "Datei auswählen",
|
||||
"ACTIVATEPREVIEW": "Konfiguration übernehmen",
|
||||
@ -1495,12 +1495,12 @@
|
||||
"TYPE": "Typ",
|
||||
"MULTIFACTORTYPES": {
|
||||
"0": "Unknown",
|
||||
"1": "U2F with Pin"
|
||||
"1": "Fingerabdruck, Security Keys, Face ID und andere"
|
||||
},
|
||||
"SECONDFACTORTYPES": {
|
||||
"0": "Unknown",
|
||||
"1": "OTP",
|
||||
"2": "U2F"
|
||||
"1": "One Time Password (OTP)",
|
||||
"2": "Fingerabdruck, Security Keys, Face ID und andere"
|
||||
}
|
||||
},
|
||||
"LOGINPOLICY": {
|
||||
|
@ -273,12 +273,12 @@
|
||||
"U2F_DIALOG_TITLE": "Verify authenticator",
|
||||
"U2F_DIALOG_DESCRIPTION": "Enter a name for your used passwordless Login",
|
||||
"U2F_SUCCESS": "Passwordless Auth created successfully!",
|
||||
"U2F_ERROR": "An error during U2F setup occurred!",
|
||||
"U2F_ERROR": "An error during setup occurred!",
|
||||
"U2F_NAME": "Authenticator Name",
|
||||
"TYPE": {
|
||||
"0": "No MFA defined",
|
||||
"1": "OTP",
|
||||
"2": "U2F"
|
||||
"1": "One Time Password (OTP)",
|
||||
"2": "Fingerprint, Security Keys, Face ID and other"
|
||||
},
|
||||
"STATE": {
|
||||
"0": "No State",
|
||||
@ -324,16 +324,16 @@
|
||||
"OTP": "OTP (One-Time Password)",
|
||||
"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.",
|
||||
"U2F": "U2F (Universal 2nd Factor)",
|
||||
"U2F_DIALOG_TITLE": "Verify U2F",
|
||||
"U2F": "Fingerprint, Security Keys, Face ID and other",
|
||||
"U2F_DIALOG_TITLE": "Verify Factor",
|
||||
"U2F_DIALOG_DESCRIPTION": "Enter a name for your used universal Multifactor.",
|
||||
"U2F_SUCCESS": "U2F created successfully!",
|
||||
"U2F_ERROR": "An error during U2F setup occurred!",
|
||||
"U2F_NAME": "U2F Name",
|
||||
"U2F_SUCCESS": "Factor added successfully!",
|
||||
"U2F_ERROR": "An error during setup occurred!",
|
||||
"U2F_NAME": "Authenticator Name",
|
||||
"TYPE": {
|
||||
"0": "No MFA defined",
|
||||
"1": "OTP",
|
||||
"2": "U2F"
|
||||
"1": "One Time Password (OTP)",
|
||||
"2": "Fingerprint, Security Keys, Face ID and other"
|
||||
},
|
||||
"STATE": {
|
||||
"0": "No State",
|
||||
@ -558,7 +558,7 @@
|
||||
"PHONEVERIFICATIONSENT": "Phone verification code sent.",
|
||||
"EMAILVERIFICATIONSENT": "E-mail verification code sent.",
|
||||
"OTPREMOVED": "OTP removed.",
|
||||
"U2FREMOVED": "U2F removed.",
|
||||
"U2FREMOVED": "Factor removed.",
|
||||
"PASSWORDLESSREMOVED": "Passwordless removed.",
|
||||
"INITIALPASSWORDSET": "Initial password set.",
|
||||
"PASSWORDNOTIFICATIONSENT": "Password change notification sent.",
|
||||
@ -1495,12 +1495,12 @@
|
||||
"TYPE": "Type",
|
||||
"MULTIFACTORTYPES": {
|
||||
"0": "Unknown",
|
||||
"1": "U2F with Pin"
|
||||
"1": "Fingerprint, Security Keys, Face ID and other"
|
||||
},
|
||||
"SECONDFACTORTYPES": {
|
||||
"0": "Unknown",
|
||||
"1": "OTP",
|
||||
"2": "U2F"
|
||||
"1": "One Time Password (OTP)",
|
||||
"2": "Fingerprint, Security Keys, Face ID and other"
|
||||
}
|
||||
},
|
||||
"LOGINPOLICY": {
|
||||
|
@ -273,12 +273,12 @@
|
||||
"U2F_DIALOG_TITLE": "Verifica autenticatore",
|
||||
"U2F_DIALOG_DESCRIPTION": "Inserisci un nome per il tuo authenticatore o dispositivo usato.",
|
||||
"U2F_SUCCESS": "Autorizzazione passwordless creata con successo!",
|
||||
"U2F_ERROR": "Si \u00e8 verificato un errore durante la configurazione di U2F!",
|
||||
"U2F_ERROR": "Si \u00e8 verificato un errore durante la configurazione!",
|
||||
"U2F_NAME": "Nome dell'autenticatore",
|
||||
"TYPE": {
|
||||
"0": "Nessun MFA definito",
|
||||
"1": "OTP",
|
||||
"2": "U2F"
|
||||
"1": "One Time Password (OTP)",
|
||||
"2": "Impronta digitale, chiave di sicurezza, Face ID e altri"
|
||||
},
|
||||
"STATE": {
|
||||
"0": "Nessuno Stato",
|
||||
@ -324,16 +324,16 @@
|
||||
"OTP": "OTP (One-Time Password)",
|
||||
"OTP_DIALOG_TITLE": "Aggiungi 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": "U2F (Universal 2nd Factor)",
|
||||
"U2F_DIALOG_TITLE": "Verifica U2F",
|
||||
"U2F": "Impronta digitale, chiave di sicurezza, Face ID e altri",
|
||||
"U2F_DIALOG_TITLE": "Verifica Fattore",
|
||||
"U2F_DIALOG_DESCRIPTION": "Inserisci un nome per il tuo methodo o dispositivo.",
|
||||
"U2F_SUCCESS": "U2F creato con successo!",
|
||||
"U2F_ERROR": "Si \u00e8 verificato un errore durante la configurazione di U2F!",
|
||||
"U2F_NAME": "Nome U2F",
|
||||
"U2F_SUCCESS": "Fattore aggiunto con successo!",
|
||||
"U2F_ERROR": "Si \u00e8 verificato un errore durante la configurazione!",
|
||||
"U2F_NAME": "Nome dell'autenticatore",
|
||||
"TYPE": {
|
||||
"0": "Nessun altro fattore definito",
|
||||
"1": "OTP",
|
||||
"2": "U2F"
|
||||
"1": "One Time Password (OTP)",
|
||||
"2": "Impronta digitale, chiave di sicurezza, Face ID e altri"
|
||||
},
|
||||
"STATE": {
|
||||
"0": "Nessuno Stato",
|
||||
@ -557,8 +557,8 @@
|
||||
"PHONEVERIFIED": "Telefono verificato con successo.",
|
||||
"PHONEVERIFICATIONSENT": "Codice di verifica telefonica inviato.",
|
||||
"EMAILVERIFICATIONSENT": "Codice di verifica e-mail inviato.",
|
||||
"OTPREMOVED": "OTP rimosso.",
|
||||
"U2FREMOVED": "U2F rimosso.",
|
||||
"OTPREMOVED": "One Time Password (OTP) rimosso.",
|
||||
"U2FREMOVED": "Fattore rimosso.",
|
||||
"PASSWORDLESSREMOVED": "Rimosso senza password.",
|
||||
"INITIALPASSWORDSET": "Password iniziale impostata.",
|
||||
"PASSWORDNOTIFICATIONSENT": "Notifica di cambio password inviata.",
|
||||
@ -1495,12 +1495,12 @@
|
||||
"TYPE": "Tipo",
|
||||
"MULTIFACTORTYPES": {
|
||||
"0": "Sconosciuto",
|
||||
"1": "U2F con Pin"
|
||||
"1": "Impronta digitale, chiave di sicurezza, Face ID e altri"
|
||||
},
|
||||
"SECONDFACTORTYPES": {
|
||||
"0": "Sconosciuto",
|
||||
"1": "OTP",
|
||||
"2": "U2F"
|
||||
"1": "One Time Password (OTP)",
|
||||
"2": "Impronta digitale, chiave di sicurezza, Face ID e altri"
|
||||
}
|
||||
},
|
||||
"LOGINPOLICY": {
|
||||
|
1
console/src/assets/mdi/usb-flash-drive-outline.svg
Normal file
1
console/src/assets/mdi/usb-flash-drive-outline.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M8 13C9.66 13 11 14.34 11 16C11 17.66 9.66 19 8 19C6.34 19 5 17.66 5 16C5 14.34 6.34 13 8 13M8 15C7.45 15 7 15.45 7 16C7 16.55 7.45 17 8 17C8.55 17 9 16.55 9 16C9 15.45 8.55 15 8 15M9.77 4.33L10.5 5.08L14.29 1.29C14.47 1.11 14.72 1 15 1C15.28 1 15.53 1.11 15.71 1.29L22.78 8.36L22.78 8.37C22.92 8.54 23 8.76 23 9C23 9.3 22.87 9.57 22.66 9.76L22.66 9.76L18.93 13.5L19.67 14.23L12.95 20.95C11.68 22.22 9.93 23 8 23C4.13 23 1 19.87 1 16C1 14.07 1.78 12.32 3.05 11.05L9.77 4.33M11.54 19.54L16.84 14.23L9.77 7.16L4.46 12.46C3.56 13.37 3 14.62 3 16C3 18.76 5.24 21 8 21C9.38 21 10.63 20.44 11.54 19.54M15.07 4.69L16.5 6.1L15.07 7.5L13.66 6.1L15.07 4.69M17.9 7.5L19.31 8.93L17.9 10.34L16.5 8.93L17.9 7.5M20.59 9L15 3.41L11.93 6.5L17.5 12.08L20.59 9Z" /></svg>
|
After Width: | Height: | Size: 1.0 KiB |
@ -51,7 +51,7 @@
|
||||
@import 'src/app/pages/actions/add-action-dialog/add-action-dialog.component';
|
||||
@import 'src/app/modules/project-role-chip/project-role-chip.component';
|
||||
@import 'src/app/pages/home/home.component.scss';
|
||||
@import 'src/app/modules/policies/login-policy/mfa-table/mfa-table.component.scss';
|
||||
@import 'src/app/modules/policies/login-policy/factor-table/factor-table.component.scss';
|
||||
@import 'src/app/modules/info-overlay/info-overlay.component.scss';
|
||||
@import './styles/codemirror.scss';
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user