From a674f99c2d1d62dfa73a81f3feb2615197e07123 Mon Sep 17 00:00:00 2001 From: Max Peintner Date: Fri, 13 May 2022 16:12:58 +0200 Subject: [PATCH] feat(console-v2): secret generator settings (#3619) * secret generator, fix project grant * secret generators --- .../notification-settings.component.ts | 6 - ...dialog-add-secret-generator.component.html | 81 +++++++++++++ ...dialog-add-secret-generator.component.scss | 43 +++++++ .../dialog-add-secret-generator.component.ts | 91 +++++++++++++++ .../secret-generator.component.html | 15 +++ .../secret-generator.component.scss | 29 +++++ .../secret-generator.component.spec.ts | 24 ++++ .../secret-generator.component.ts | 107 ++++++++++++++++++ .../secret-generator.module.ts | 35 ++++++ .../project-members.component.ts | 2 - .../settings-list.component.html | 4 + .../settings-list/settings-list.module.ts | 2 + .../src/app/modules/settings-list/settings.ts | 5 + .../app/pages/domains/domains.component.scss | 1 - .../instance-settings.component.ts | 2 + .../project-grant-create.component.scss | 1 + .../project-grant-create.component.ts | 60 ++++++---- console/src/app/services/admin.service.ts | 21 ++++ console/src/app/services/toast.service.ts | 80 +++++++------ console/src/assets/i18n/de.json | 24 +++- console/src/assets/i18n/en.json | 24 +++- console/src/assets/i18n/it.json | 24 +++- console/src/component-themes.scss | 2 + console/src/styles/toast.scss | 22 ++++ 24 files changed, 636 insertions(+), 69 deletions(-) create mode 100644 console/src/app/modules/policies/secret-generator/dialog-add-secret-generator/dialog-add-secret-generator.component.html create mode 100644 console/src/app/modules/policies/secret-generator/dialog-add-secret-generator/dialog-add-secret-generator.component.scss create mode 100644 console/src/app/modules/policies/secret-generator/dialog-add-secret-generator/dialog-add-secret-generator.component.ts create mode 100644 console/src/app/modules/policies/secret-generator/secret-generator.component.html create mode 100644 console/src/app/modules/policies/secret-generator/secret-generator.component.scss create mode 100644 console/src/app/modules/policies/secret-generator/secret-generator.component.spec.ts create mode 100644 console/src/app/modules/policies/secret-generator/secret-generator.component.ts create mode 100644 console/src/app/modules/policies/secret-generator/secret-generator.module.ts create mode 100644 console/src/styles/toast.scss diff --git a/console/src/app/modules/policies/notification-settings/notification-settings.component.ts b/console/src/app/modules/policies/notification-settings/notification-settings.component.ts index c97418bbe..f2bfc3445 100644 --- a/console/src/app/modules/policies/notification-settings/notification-settings.component.ts +++ b/console/src/app/modules/policies/notification-settings/notification-settings.component.ts @@ -109,12 +109,6 @@ export class NotificationSettingsComponent implements OnInit { public addSMSProvider(): void { const dialogRef = this.dialog.open(DialogAddSMSProviderComponent, { - data: { - confirmKey: 'ACTIONS.DELETE', - cancelKey: 'ACTIONS.CANCEL', - titleKey: 'IDP.DELETE_TITLE', - descriptionKey: 'IDP.DELETE_DESCRIPTION', - }, width: '400px', }); diff --git a/console/src/app/modules/policies/secret-generator/dialog-add-secret-generator/dialog-add-secret-generator.component.html b/console/src/app/modules/policies/secret-generator/dialog-add-secret-generator/dialog-add-secret-generator.component.html new file mode 100644 index 000000000..e4c360092 --- /dev/null +++ b/console/src/app/modules/policies/secret-generator/dialog-add-secret-generator/dialog-add-secret-generator.component.html @@ -0,0 +1,81 @@ +

+ {{ 'SETTING.SECRETS.ADDGENERATOR' | translate }} +

+
+
+ + {{ 'SETTING.SECRETS.GENERATORTYPE' | translate }} + + + {{ 'SETTING.SECRETS.TYPE.' + gen | translate }} + + + + +

{{ 'SETTING.SECRETS.TYPE.' + generatorType?.value | translate }}

+ + + {{ 'SETTING.SECRETS.EXPIRY' | translate }} + + + + + {{ 'SETTING.SECRETS.LENGTH' | translate }} + + + +
+ +
+ + {{ 'SETTING.SECRETS.INCLUDEDIGITS' | translate }} +
+
+ + +
+ + {{ 'SETTING.SECRETS.INCLUDESYMBOLS' | translate }} +
+
+ + +
+ + {{ 'SETTING.SECRETS.INCLUDELOWERLETTERS' | translate }} +
+
+ + +
+ + {{ 'SETTING.SECRETS.INCLUDEUPPERLETTERS' | translate }} +
+
+
+
+
+
+ + +
diff --git a/console/src/app/modules/policies/secret-generator/dialog-add-secret-generator/dialog-add-secret-generator.component.scss b/console/src/app/modules/policies/secret-generator/dialog-add-secret-generator/dialog-add-secret-generator.component.scss new file mode 100644 index 000000000..638a86322 --- /dev/null +++ b/console/src/app/modules/policies/secret-generator/dialog-add-secret-generator/dialog-add-secret-generator.component.scss @@ -0,0 +1,43 @@ +.title { + font-size: 1.5rem; +} + +.generator-type { + font-size: 1rem; +} + +.type-form-field { + display: none; +} + +.generator-form-field { + width: 100%; +} + +.slide-toggle-wrapper { + display: grid; + grid-template-columns: 1fr; + column-gap: 1rem; + + .slide-toggle { + margin: 0.5rem 0; + + .slide-toggle-row { + display: flex; + align-items: center; + + .icon { + margin: 0 0.5rem; + } + } + } +} + +.action { + display: flex; + justify-content: space-between; + + button { + border-radius: 0.5rem; + } +} diff --git a/console/src/app/modules/policies/secret-generator/dialog-add-secret-generator/dialog-add-secret-generator.component.ts b/console/src/app/modules/policies/secret-generator/dialog-add-secret-generator/dialog-add-secret-generator.component.ts new file mode 100644 index 000000000..fe977eedc --- /dev/null +++ b/console/src/app/modules/policies/secret-generator/dialog-add-secret-generator/dialog-add-secret-generator.component.ts @@ -0,0 +1,91 @@ +import { Component, Inject } from '@angular/core'; +import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { Duration } from 'google-protobuf/google/protobuf/duration_pb'; +import { UpdateSecretGeneratorRequest } from 'src/app/proto/generated/zitadel/admin_pb'; +import { SecretGeneratorType } from 'src/app/proto/generated/zitadel/settings_pb'; + +@Component({ + selector: 'cnsl-dialog-add-secret-generator', + templateUrl: './dialog-add-secret-generator.component.html', + styleUrls: ['./dialog-add-secret-generator.component.scss'], +}) +export class DialogAddSecretGeneratorComponent { + public SecretGeneratorType: any = SecretGeneratorType; + public availableGenerators: SecretGeneratorType[] = [ + SecretGeneratorType.SECRET_GENERATOR_TYPE_INIT_CODE, + SecretGeneratorType.SECRET_GENERATOR_TYPE_VERIFY_EMAIL_CODE, + SecretGeneratorType.SECRET_GENERATOR_TYPE_VERIFY_PHONE_CODE, + SecretGeneratorType.SECRET_GENERATOR_TYPE_PASSWORD_RESET_CODE, + SecretGeneratorType.SECRET_GENERATOR_TYPE_PASSWORDLESS_INIT_CODE, + SecretGeneratorType.SECRET_GENERATOR_TYPE_APP_SECRET, + ]; + public req: UpdateSecretGeneratorRequest = new UpdateSecretGeneratorRequest(); + + public specsForm!: FormGroup; + + constructor( + private fb: FormBuilder, + public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: any, + ) { + this.specsForm = this.fb.group({ + generatorType: [SecretGeneratorType.SECRET_GENERATOR_TYPE_APP_SECRET, [Validators.required]], + expiry: [1, [Validators.required]], + includeDigits: [true, [Validators.required]], + includeLowerLetters: [true, [Validators.required]], + includeSymbols: [true, [Validators.required]], + includeUpperLetters: [true, [Validators.required]], + length: [6, [Validators.required]], + }); + + this.generatorType?.setValue(data.type); + } + + public closeDialog(): void { + this.dialogRef.close(); + } + + public closeDialogWithRequest(): void { + this.req.setGeneratorType(this.generatorType?.value); + + const expiry = new Duration().setSeconds((this.expiry?.value ?? 1) * 60 * 60); + + this.req.setExpiry(expiry); + this.req.setIncludeDigits(this.includeDigits?.value); + this.req.setIncludeLowerLetters(this.includeLowerLetters?.value); + this.req.setIncludeSymbols(this.includeSymbols?.value); + this.req.setIncludeUpperLetters(this.includeUpperLetters?.value); + this.req.setLength(this.length?.value); + + this.dialogRef.close(this.req); + } + + public get generatorType(): AbstractControl | null { + return this.specsForm.get('generatorType'); + } + + public get expiry(): AbstractControl | null { + return this.specsForm.get('expiry'); + } + + public get includeDigits(): AbstractControl | null { + return this.specsForm.get('includeDigits'); + } + + public get includeLowerLetters(): AbstractControl | null { + return this.specsForm.get('includeLowerLetters'); + } + + public get includeSymbols(): AbstractControl | null { + return this.specsForm.get('includeSymbols'); + } + + public get includeUpperLetters(): AbstractControl | null { + return this.specsForm.get('includeUpperLetters'); + } + + public get length(): AbstractControl | null { + return this.specsForm.get('length'); + } +} diff --git a/console/src/app/modules/policies/secret-generator/secret-generator.component.html b/console/src/app/modules/policies/secret-generator/secret-generator.component.html new file mode 100644 index 000000000..2095bf31c --- /dev/null +++ b/console/src/app/modules/policies/secret-generator/secret-generator.component.html @@ -0,0 +1,15 @@ +
+ +
+

{{ 'SETTING.SECRETS.TITLE' | translate }}

+ +
+ +
+

{{ 'SETTING.SECRETS.TYPE.' + gen | translate }}

+ +
+
+
diff --git a/console/src/app/modules/policies/secret-generator/secret-generator.component.scss b/console/src/app/modules/policies/secret-generator/secret-generator.component.scss new file mode 100644 index 000000000..eeb77dcbe --- /dev/null +++ b/console/src/app/modules/policies/secret-generator/secret-generator.component.scss @@ -0,0 +1,29 @@ +.spinner-wr { + margin: 0.5rem 0; +} + +.generators { + display: grid; + grid-template-columns: 1fr 1fr; + column-gap: 1rem; + row-gap: 1rem; + margin-bottom: 2rem; + margin-top: 1.5rem; + + @media only screen and (max-width: 600px) { + grid-template-columns: 1fr; + } + + .generator { + .row { + display: flex; + align-items: center; + justify-content: space-between; + + .title { + font-size: 1rem; + margin: 0; + } + } + } +} diff --git a/console/src/app/modules/policies/secret-generator/secret-generator.component.spec.ts b/console/src/app/modules/policies/secret-generator/secret-generator.component.spec.ts new file mode 100644 index 000000000..7548a3230 --- /dev/null +++ b/console/src/app/modules/policies/secret-generator/secret-generator.component.spec.ts @@ -0,0 +1,24 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SecretGeneratorComponent } from './secret-generator.component'; + +describe('OIDCConfigurationComponent', () => { + let component: SecretGeneratorComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [SecretGeneratorComponent], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(SecretGeneratorComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/console/src/app/modules/policies/secret-generator/secret-generator.component.ts b/console/src/app/modules/policies/secret-generator/secret-generator.component.ts new file mode 100644 index 000000000..dc1e64497 --- /dev/null +++ b/console/src/app/modules/policies/secret-generator/secret-generator.component.ts @@ -0,0 +1,107 @@ +import { Component, OnInit } from '@angular/core'; +import { MatDialog } from '@angular/material/dialog'; +import { UpdateSecretGeneratorRequest, UpdateSecretGeneratorResponse } from 'src/app/proto/generated/zitadel/admin_pb'; +import { OIDCSettings, SecretGenerator, SecretGeneratorType } from 'src/app/proto/generated/zitadel/settings_pb'; +import { AdminService } from 'src/app/services/admin.service'; +import { ToastService } from 'src/app/services/toast.service'; + +import { DialogAddSecretGeneratorComponent } from './dialog-add-secret-generator/dialog-add-secret-generator.component'; + +@Component({ + selector: 'cnsl-secret-generator', + templateUrl: './secret-generator.component.html', + styleUrls: ['./secret-generator.component.scss'], +}) +export class SecretGeneratorComponent implements OnInit { + public generators: SecretGenerator.AsObject[] = []; + public oidcSettings!: OIDCSettings.AsObject; + + public loading: boolean = false; + + public readonly AVAILABLEGENERATORS: SecretGeneratorType[] = [ + SecretGeneratorType.SECRET_GENERATOR_TYPE_INIT_CODE, + SecretGeneratorType.SECRET_GENERATOR_TYPE_VERIFY_EMAIL_CODE, + SecretGeneratorType.SECRET_GENERATOR_TYPE_VERIFY_PHONE_CODE, + SecretGeneratorType.SECRET_GENERATOR_TYPE_PASSWORD_RESET_CODE, + SecretGeneratorType.SECRET_GENERATOR_TYPE_PASSWORDLESS_INIT_CODE, + SecretGeneratorType.SECRET_GENERATOR_TYPE_APP_SECRET, + ]; + constructor(private service: AdminService, private toast: ToastService, private dialog: MatDialog) {} + + ngOnInit(): void { + this.fetchData(); + } + + private fetchData(): void { + this.service + .listSecretGenerators() + .then((generators) => { + if (generators.resultList) { + this.generators = generators.resultList; + console.log(this.generators); + } + }) + .catch((error) => { + if (error.code === 5) { + } else { + this.toast.showError(error); + } + }); + } + + private updateData(): Promise | void { + const dialogRef = this.dialog.open(DialogAddSecretGeneratorComponent, { + data: {}, + width: '400px', + }); + + dialogRef.afterClosed().subscribe((req: UpdateSecretGeneratorRequest) => { + if (req) { + return (this.service as AdminService).updateSecretGenerator(req); + } else { + return; + } + }); + } + + public openGeneratorDialog(generatorType: SecretGeneratorType): void { + const dialogRef = this.dialog.open(DialogAddSecretGeneratorComponent, { + data: { + type: generatorType, + }, + width: '400px', + }); + + dialogRef.afterClosed().subscribe((req: UpdateSecretGeneratorRequest) => { + if (req) { + return (this.service as AdminService) + .updateSecretGenerator(req) + .then(() => { + this.toast.showInfo('SETTING.SECRETS.UPDATED', true); + }) + .catch((error) => { + this.toast.showError(error); + }); + } else { + return; + } + }); + } + + public savePolicy(): void { + const prom = this.updateData(); + if (prom) { + prom + .then(() => { + this.toast.showInfo('SETTING.SMTP.SAVED', true); + this.loading = true; + setTimeout(() => { + this.fetchData(); + }, 2000); + }) + .catch((error) => { + this.toast.showError(error); + }); + } + } +} diff --git a/console/src/app/modules/policies/secret-generator/secret-generator.module.ts b/console/src/app/modules/policies/secret-generator/secret-generator.module.ts new file mode 100644 index 000000000..3c031ec9d --- /dev/null +++ b/console/src/app/modules/policies/secret-generator/secret-generator.module.ts @@ -0,0 +1,35 @@ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { MatSelectModule } from '@angular/material/select'; +import { MatSlideToggleModule } from '@angular/material/slide-toggle'; +import { TranslateModule } from '@ngx-translate/core'; + +import { CardModule } from '../../card/card.module'; +import { FormFieldModule } from '../../form-field/form-field.module'; +import { InputModule } from '../../input/input.module'; +import { DialogAddSecretGeneratorComponent } from './dialog-add-secret-generator/dialog-add-secret-generator.component'; +import { SecretGeneratorComponent } from './secret-generator.component'; + +@NgModule({ + declarations: [SecretGeneratorComponent, DialogAddSecretGeneratorComponent], + imports: [ + CommonModule, + MatIconModule, + CardModule, + FormsModule, + MatButtonModule, + FormFieldModule, + ReactiveFormsModule, + MatSlideToggleModule, + InputModule, + MatProgressSpinnerModule, + MatSelectModule, + TranslateModule, + ], + exports: [SecretGeneratorComponent, DialogAddSecretGeneratorComponent], +}) +export class SecretGeneratorModule {} diff --git a/console/src/app/modules/project-members/project-members.component.ts b/console/src/app/modules/project-members/project-members.component.ts index 49ac969ef..93281c6e8 100644 --- a/console/src/app/modules/project-members/project-members.component.ts +++ b/console/src/app/modules/project-members/project-members.component.ts @@ -77,11 +77,9 @@ export class ProjectMembersComponent { }), new Breadcrumb({ type: BreadcrumbType.PROJECT, - // name: this.project.name, param: { key: 'projectid', value: (this.project as Project.AsObject).id }, routerLink: ['/projects', (this.project as Project.AsObject).id], isZitadel: isZitadel, - hideNav: true, }), ]; breadcrumbService.setBreadcrumb(breadcrumbs); diff --git a/console/src/app/modules/settings-list/settings-list.component.html b/console/src/app/modules/settings-list/settings-list.component.html index 7e7414ff4..a408900b7 100644 --- a/console/src/app/modules/settings-list/settings-list.component.html +++ b/console/src/app/modules/settings-list/settings-list.component.html @@ -30,6 +30,10 @@ + + + + diff --git a/console/src/app/modules/settings-list/settings-list.module.ts b/console/src/app/modules/settings-list/settings-list.module.ts index 2f839906c..4c1e17cc7 100644 --- a/console/src/app/modules/settings-list/settings-list.module.ts +++ b/console/src/app/modules/settings-list/settings-list.module.ts @@ -17,6 +17,7 @@ import { PasswordComplexityPolicyModule } from '../policies/password-complexity- import { PasswordLockoutPolicyModule } from '../policies/password-lockout-policy/password-lockout-policy.module'; import { PrivacyPolicyModule } from '../policies/privacy-policy/privacy-policy.module'; import { PrivateLabelingPolicyModule } from '../policies/private-labeling-policy/private-labeling-policy.module'; +import { SecretGeneratorModule } from '../policies/secret-generator/secret-generator.module'; import { SidenavModule } from '../sidenav/sidenav.module'; import { SettingsListComponent } from './settings-list.component'; @@ -41,6 +42,7 @@ import { SettingsListComponent } from './settings-list.component'; HasRolePipeModule, NotificationSettingsModule, OIDCConfigurationModule, + SecretGeneratorModule, ], exports: [SettingsListComponent], }) diff --git a/console/src/app/modules/settings-list/settings.ts b/console/src/app/modules/settings-list/settings.ts index 011ada8d7..2050ef3be 100644 --- a/console/src/app/modules/settings-list/settings.ts +++ b/console/src/app/modules/settings-list/settings.ts @@ -10,6 +10,11 @@ export const OIDC: SidenavSetting = { i18nKey: 'SETTINGS.LIST.OIDC', }; +export const SECRETS: SidenavSetting = { + id: 'secrets', + i18nKey: 'SETTINGS.LIST.SECRETS', +}; + export const LOGIN: SidenavSetting = { id: 'login', i18nKey: 'SETTINGS.LIST.LOGIN', diff --git a/console/src/app/pages/domains/domains.component.scss b/console/src/app/pages/domains/domains.component.scss index cbe4876e5..65396b2b0 100644 --- a/console/src/app/pages/domains/domains.component.scss +++ b/console/src/app/pages/domains/domains.component.scss @@ -38,7 +38,6 @@ display: flex; flex-direction: row; align-items: center; - margin-bottom: -0.5rem; .title { font-size: 16px; diff --git a/console/src/app/pages/instance-settings/instance-settings.component.ts b/console/src/app/pages/instance-settings/instance-settings.component.ts index 1eeecbe88..b1ae05306 100644 --- a/console/src/app/pages/instance-settings/instance-settings.component.ts +++ b/console/src/app/pages/instance-settings/instance-settings.component.ts @@ -17,6 +17,7 @@ import { NOTIFICATIONS, OIDC, PRIVACYPOLICY, + SECRETS, } from '../../modules/settings-list/settings'; @Component({ @@ -43,6 +44,7 @@ export class InstanceSettingsComponent { // others PRIVACYPOLICY, OIDC, + SECRETS, ]; constructor(breadcrumbService: BreadcrumbService, activatedRoute: ActivatedRoute) { const breadcrumbs = [ diff --git a/console/src/app/pages/projects/owned-projects/project-grant-create/project-grant-create.component.scss b/console/src/app/pages/projects/owned-projects/project-grant-create/project-grant-create.component.scss index 7df73ab32..f2fd39dd0 100644 --- a/console/src/app/pages/projects/owned-projects/project-grant-create/project-grant-create.component.scss +++ b/console/src/app/pages/projects/owned-projects/project-grant-create/project-grant-create.component.scss @@ -35,6 +35,7 @@ .domain-button { margin-right: 1rem; margin-bottom: 1rem; + display: block; } .btn-container { diff --git a/console/src/app/pages/projects/owned-projects/project-grant-create/project-grant-create.component.ts b/console/src/app/pages/projects/owned-projects/project-grant-create/project-grant-create.component.ts index 3f942f81d..99ac5e3e3 100644 --- a/console/src/app/pages/projects/owned-projects/project-grant-create/project-grant-create.component.ts +++ b/console/src/app/pages/projects/owned-projects/project-grant-create/project-grant-create.component.ts @@ -1,13 +1,15 @@ import { Location } from '@angular/common'; import { Component, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; -import { Subscription } from 'rxjs'; +import { Subject, takeUntil } from 'rxjs'; import { Org } from 'src/app/proto/generated/zitadel/org_pb'; import { Role } from 'src/app/proto/generated/zitadel/project_pb'; -import { GrpcAuthService } from 'src/app/services/grpc-auth.service'; +import { Breadcrumb, BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service'; import { ManagementService } from 'src/app/services/mgmt.service'; import { ToastService } from 'src/app/services/toast.service'; +const ROUTEPARAM = 'projectid'; + @Component({ selector: 'cnsl-project-grant-create', templateUrl: './project-grant-create.component.html', @@ -22,39 +24,52 @@ export class ProjectGrantCreateComponent implements OnInit, OnDestroy { public STEPS: number = 2; public currentCreateStep: number = 1; - private routeSubscription: Subscription = new Subscription(); + private destroy$: Subject = new Subject(); constructor( private route: ActivatedRoute, private toast: ToastService, private mgmtService: ManagementService, - private authService: GrpcAuthService, private _location: Location, - ) { } + private breadcrumbService: BreadcrumbService, + ) {} public ngOnInit(): void { - this.routeSubscription = this.route.params.subscribe(params => { + this.route.params.pipe(takeUntil(this.destroy$)).subscribe((params) => { this.projectId = params.projectid; + + const breadcrumbs = [ + new Breadcrumb({ + type: BreadcrumbType.ORG, + routerLink: ['/org'], + }), + new Breadcrumb({ + type: BreadcrumbType.PROJECT, + name: '', + param: { key: ROUTEPARAM, value: this.projectId }, + routerLink: ['/projects', this.projectId], + }), + ]; + this.breadcrumbService.setBreadcrumb(breadcrumbs); }); } public ngOnDestroy(): void { - this.routeSubscription.unsubscribe(); + this.destroy$.next(); + this.destroy$.complete(); } public searchOrg(domain: string): void { - this.mgmtService.getOrgByDomainGlobal(domain).then((ret) => { - if (ret.org) { - const tmp = ret.org; - this.authService.getActiveOrg().then((org) => { - if (tmp !== org) { - this.org = tmp; - } - }); - this.org = ret.org; - } - }).catch(error => { - this.toast.showError(error); - }); + this.mgmtService + .getOrgByDomainGlobal(domain) + .then((ret) => { + if (ret.org) { + const tmp = ret.org; + this.org = tmp; + } + }) + .catch((error) => { + this.toast.showError(error); + }); } public close(): void { @@ -67,13 +82,13 @@ export class ProjectGrantCreateComponent implements OnInit, OnDestroy { .then(() => { this.close(); }) - .catch(error => { + .catch((error) => { this.toast.showError(error); }); } public selectRoles(roles: Role.AsObject[]): void { - this.rolesKeyList = roles.map(role => role.key); + this.rolesKeyList = roles.map((role) => role.key); } public next(): void { @@ -84,4 +99,3 @@ export class ProjectGrantCreateComponent implements OnInit, OnDestroy { this.currentCreateStep--; } } - diff --git a/console/src/app/services/admin.service.ts b/console/src/app/services/admin.service.ts index fded3b3da..955b5d265 100644 --- a/console/src/app/services/admin.service.ts +++ b/console/src/app/services/admin.service.ts @@ -77,6 +77,8 @@ import { GetPreviewLabelPolicyResponse, GetPrivacyPolicyRequest, GetPrivacyPolicyResponse, + GetSecretGeneratorRequest, + GetSecretGeneratorResponse, GetSMSProviderRequest, GetSMSProviderResponse, GetSMTPConfigRequest, @@ -98,6 +100,8 @@ import { ListLoginPolicyMultiFactorsResponse, ListLoginPolicySecondFactorsRequest, ListLoginPolicySecondFactorsResponse, + ListSecretGeneratorsRequest, + ListSecretGeneratorsResponse, ListSMSProvidersRequest, ListSMSProvidersResponse, ListViewsRequest, @@ -174,6 +178,8 @@ import { UpdatePasswordComplexityPolicyResponse, UpdatePrivacyPolicyRequest, UpdatePrivacyPolicyResponse, + UpdateSecretGeneratorRequest, + UpdateSecretGeneratorResponse, UpdateSMTPConfigPasswordRequest, UpdateSMTPConfigPasswordResponse, UpdateSMTPConfigRequest, @@ -579,6 +585,21 @@ export class AdminService { return this.grpcService.admin.getFileSystemNotificationProvider(req, null).then((resp) => resp.toObject()); } + /* secrets generator */ + + public listSecretGenerators(): Promise { + const req = new ListSecretGeneratorsRequest(); + return this.grpcService.admin.listSecretGenerators(req, null).then((resp) => resp.toObject()); + } + + public getSecretGenerator(req: GetSecretGeneratorRequest): Promise { + return this.grpcService.admin.getSecretGenerator(req, null).then((resp) => resp.toObject()); + } + + public updateSecretGenerator(req: UpdateSecretGeneratorRequest): Promise { + return this.grpcService.admin.updateSecretGenerator(req, null).then((resp) => resp.toObject()); + } + /* org iam */ public getCustomOrgIAMPolicy(orgId: string): Promise { diff --git a/console/src/app/services/toast.service.ts b/console/src/app/services/toast.service.ts index 0b06e4843..c881dcd92 100644 --- a/console/src/app/services/toast.service.ts +++ b/console/src/app/services/toast.service.ts @@ -1,49 +1,61 @@ import { Injectable } from '@angular/core'; -import { MatSnackBar } from '@angular/material/snack-bar'; +import { MatSnackBar, MatSnackBarHorizontalPosition, MatSnackBarVerticalPosition } from '@angular/material/snack-bar'; import { TranslateService } from '@ngx-translate/core'; import { Observable } from 'rxjs'; import { take } from 'rxjs/operators'; @Injectable({ - providedIn: 'root', + providedIn: 'root', }) export class ToastService { - constructor( - private snackBar: MatSnackBar, - private translate: TranslateService, - ) {} + horizontalPosition: MatSnackBarHorizontalPosition = 'end'; + verticalPosition: MatSnackBarVerticalPosition = 'top'; - public showInfo(message: string, i18nkey: boolean = false): void { - if (i18nkey) { - this.translate - .get(message) - .subscribe(data => { - this.translate.get('ACTIONS.CLOSE').pipe(take(1)).subscribe(value => { - this.showMessage(data, value, true); - }); - }); - } else { - this.translate.get('ACTIONS.CLOSE').pipe(take(1)).subscribe(value => { - this.showMessage(message, value, true); - }); - } + constructor(private snackBar: MatSnackBar, private translate: TranslateService) {} + + public showInfo(message: string, i18nkey: boolean = false): void { + if (i18nkey) { + this.translate.get(message).subscribe((data) => { + this.translate + .get('ACTIONS.CLOSE') + .pipe(take(1)) + .subscribe((value) => { + this.showMessage(data, value, true); + }); + }); + } else { + this.translate + .get('ACTIONS.CLOSE') + .pipe(take(1)) + .subscribe((value) => { + this.showMessage(message, value, true); + }); } + } - public showError(grpcError: any): void { - const { message, code, metadata } = grpcError; - if (code !== 16) { - this.translate.get('ACTIONS.CLOSE').pipe(take(1)).subscribe(value => { - this.showMessage(decodeURI(message), value, false); - }); - } + public showError(grpcError: any): void { + const { message, code, metadata } = grpcError; + if (code !== 16) { + this.translate + .get('ACTIONS.CLOSE') + .pipe(take(1)) + .subscribe((value) => { + this.showMessage(decodeURI(message), value, false); + }); } + } - private showMessage(message: string, action: string, success: boolean): Observable { - const ref = this.snackBar.open(message, action, { - duration: 4000, - panelClass: success ? "data-e2e-success" : "data-e2e-failure" - }); + private showMessage(message: string, action: string, success: boolean): Observable { + const ref = this.snackBar.open(message, action, { + data: { + message, + }, + duration: success ? 4000 : 5000, + panelClass: success ? 'data-e2e-success' : 'data-e2e-failure', + horizontalPosition: this.horizontalPosition, + verticalPosition: this.verticalPosition, + }); - return ref.onAction(); - } + return ref.onAction(); + } } diff --git a/console/src/assets/i18n/de.json b/console/src/assets/i18n/de.json index 31ac3d263..7543ee270 100644 --- a/console/src/assets/i18n/de.json +++ b/console/src/assets/i18n/de.json @@ -821,7 +821,8 @@ "LOGINTEXTS": "Login Interface Texte", "BRANDING": "Branding", "PRIVACYPOLICY": "Datenschutzrichtlinie", - "OIDC": "OIDC Konfiguration" + "OIDC": "OIDC Token Lifetime und Expiration", + "SECRETS": "Secret Erscheinungsbild" }, "GROUPS": { "NOTIFICATIONS": "Benachrichtigungen", @@ -869,6 +870,27 @@ "REFRESHTOKENIDLEEXPIRATION": "Refresh Token Idle Expiration", "INHOURS": "Stunden", "INDAYS": "Tage" + }, + "SECRETS": { + "TITLE": "Secret Erscheinungsbild", + "TYPES": "Schlüsseltypen", + "TYPE": { + "1": "Email Initialisierungscode", + "2": "Email Verifikationscode", + "3": "Telefonnummer Verificationscode", + "4": "Passwort Zurücksetzen Code", + "5": "Passwordless Initialisierungscode", + "6": "Applicationssecret" + }, + "ADDGENERATOR": "Secret Erscheinungsbild definieren", + "GENERATORTYPE": "Typ", + "EXPIRY": "Ablauf (in Stunden)", + "INCLUDEDIGITS": "Enthält Zahlen", + "INCLUDESYMBOLS": "Enthält Symbole", + "INCLUDELOWERLETTERS": "Enthält Kleinbuchstaben", + "INCLUDEUPPERLETTERS": "Enthält Grossbuchstaben", + "LENGTH": "Länge", + "UPDATED": "Einstellungen geändert" } }, "POLICY": { diff --git a/console/src/assets/i18n/en.json b/console/src/assets/i18n/en.json index b3e32db4a..62bb62bd0 100644 --- a/console/src/assets/i18n/en.json +++ b/console/src/assets/i18n/en.json @@ -821,7 +821,8 @@ "LOGINTEXTS": "Login Interface Texts", "BRANDING": "Branding", "PRIVACYPOLICY": "Privacy Policy", - "OIDC": "OIDC Configuration" + "OIDC": "OIDC Token lifetime and expiration", + "SECRETS": "Secret Appearance" }, "GROUPS": { "NOTIFICATIONS": "Notifications", @@ -869,6 +870,27 @@ "REFRESHTOKENIDLEEXPIRATION": "Refresh Token Idle Expiration", "INHOURS": "hours", "INDAYS": "Days" + }, + "SECRETS": { + "TITLE": "Secret Appearance", + "TYPES": "Secret Types", + "TYPE": { + "1": "Initialization Mail", + "2": "Email verification", + "3": "Phone verification", + "4": "Password Reset", + "5": "Passwordless Initialization", + "6": "App Secret" + }, + "ADDGENERATOR": "Define Secret Appearance", + "GENERATORTYPE": "Type", + "EXPIRY": "Expiration (in hours)", + "INCLUDEDIGITS": "Include Numbers", + "INCLUDESYMBOLS": "Include Symbols", + "INCLUDELOWERLETTERS": "Include Lower letters", + "INCLUDEUPPERLETTERS": "Include Upper letters", + "LENGTH": "Length", + "UPDATED": "Settings updated." } }, "POLICY": { diff --git a/console/src/assets/i18n/it.json b/console/src/assets/i18n/it.json index c168652f0..0b095d6fd 100644 --- a/console/src/assets/i18n/it.json +++ b/console/src/assets/i18n/it.json @@ -821,7 +821,8 @@ "LOGINTEXTS": "Testi dell'interfaccia login", "BRANDING": "Branding", "PRIVACYPOLICY": "Informativa sulla privacy e TOS", - "OIDC": "OIDC Configuration" + "OIDC": "OIDC Token lifetime e scadenza", + "SECRETS": "Aspetto dei segreti" }, "GROUPS": { "NOTIFICATIONS": "Notifiche", @@ -869,6 +870,27 @@ "REFRESHTOKENIDLEEXPIRATION": "Refresh Token Idle Expiration", "INHOURS": "ore", "INDAYS": "giorni" + }, + "SECRETS": { + "TITLE": "Aspetto dei segreti", + "TYPES": "Tipi di segreti", + "TYPE": { + "1": "Initializzazione email", + "2": "Verificazione dell' email", + "3": "Verificazione del numero di telefono", + "4": "Ripristino Password", + "5": "Inizializzazione Passwordless", + "6": "Segreto dell'applicazione" + }, + "ADDGENERATOR": "Definisci aspetto", + "GENERATORTYPE": "Tipo", + "EXPIRY": "Scadenza (in ore)", + "INCLUDEDIGITS": "Contiene numeri", + "INCLUDESYMBOLS": "Contiene simboli", + "INCLUDELOWERLETTERS": "Contiene lettere minuscole", + "INCLUDEUPPERLETTERS": "Contiene lettere maiuscole", + "LENGTH": "Lunghezza", + "UPDATED": "Impostazioni aggiornati" } }, "POLICY": { diff --git a/console/src/component-themes.scss b/console/src/component-themes.scss index deef8577c..2792c3b89 100644 --- a/console/src/component-themes.scss +++ b/console/src/component-themes.scss @@ -12,6 +12,7 @@ @import 'src/app/modules/app-card/app-card.component'; @import 'src/app/modules/contributors/contributors.component'; @import 'src/app/modules/nav/nav.component'; +@import './styles/toast.scss'; @import 'src/app/modules/table-actions/table-actions.component'; @import 'src/app/modules/org-context/org-context.component.scss'; @import 'src/app/modules/action-keys/action-keys.component.scss'; @@ -95,6 +96,7 @@ @include user-detail-theme($theme); @include instance-detail-theme($theme); @include meta-theme($theme); + @include toast-theme($theme); @include keyboard-shortcuts-theme($theme); @include project-grant-illustration-theme($theme); @include refresh-table-theme($theme); diff --git a/console/src/styles/toast.scss b/console/src/styles/toast.scss new file mode 100644 index 000000000..5ad34591a --- /dev/null +++ b/console/src/styles/toast.scss @@ -0,0 +1,22 @@ +@use '@angular/material' as mat; + +@mixin toast-theme($theme) { + $primary: map-get($theme, primary); + $primary-color: mat.get-color-from-palette($primary, 500); + $primary-light-color: mat.get-color-from-palette($primary, 200); + $warn: map-get($theme, warn); + $warn-color: mat.get-color-from-palette($warn, 500); + $background: map-get($theme, background); + $foreground: map-get($theme, foreground); + $is-dark-theme: map-get($theme, is-dark); + + // .data-e2e-success { + // background-color: map-get($background, cards) !important; + // color: var(--success) !important; + // } + + .data-e2e-failure { + background-color: $warn-color !important; + color: map-get($foreground, text) !important; + } +}