From 617f46780dd38f755d67aaf6016f10a5a2271ee8 Mon Sep 17 00:00:00 2001 From: Ryan Galletto Date: Wed, 22 Jan 2025 08:50:49 -0500 Subject: [PATCH 1/2] Update Certificate Authorities Page With Angular Components --- .../auth-policies-page.component.html | 6 +- ...ertificate-authorities-page.component.html | 20 ++ ...ertificate-authorities-page.component.scss | 8 + .../certificate-authorities-page.component.ts | 114 ++++++++++ .../certificate-authorities-page.service.ts | 196 ++++++++++++++++++ .../src/lib/ziti-console-lib.module.ts | 4 +- projects/ziti-console-lib/src/public-api.ts | 2 + 7 files changed, 346 insertions(+), 4 deletions(-) create mode 100644 projects/ziti-console-lib/src/lib/pages/certificate-authorities/certificate-authorities-page.component.html create mode 100644 projects/ziti-console-lib/src/lib/pages/certificate-authorities/certificate-authorities-page.component.scss create mode 100644 projects/ziti-console-lib/src/lib/pages/certificate-authorities/certificate-authorities-page.component.ts create mode 100644 projects/ziti-console-lib/src/lib/pages/certificate-authorities/certificate-authorities-page.service.ts diff --git a/projects/ziti-console-lib/src/lib/pages/auth-policies/auth-policies-page.component.html b/projects/ziti-console-lib/src/lib/pages/auth-policies/auth-policies-page.component.html index 810d7083..22aa697c 100644 --- a/projects/ziti-console-lib/src/lib/pages/auth-policies/auth-policies-page.component.html +++ b/projects/ziti-console-lib/src/lib/pages/auth-policies/auth-policies-page.component.html @@ -1,17 +1,17 @@ -
+
- + + + + +
diff --git a/projects/ziti-console-lib/src/lib/pages/certificate-authorities/certificate-authorities-page.component.scss b/projects/ziti-console-lib/src/lib/pages/certificate-authorities/certificate-authorities-page.component.scss new file mode 100644 index 00000000..b330fda1 --- /dev/null +++ b/projects/ziti-console-lib/src/lib/pages/certificate-authorities/certificate-authorities-page.component.scss @@ -0,0 +1,8 @@ +.certificate-authorities { + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + position: relative; + flex: 1 1 auto; +} diff --git a/projects/ziti-console-lib/src/lib/pages/certificate-authorities/certificate-authorities-page.component.ts b/projects/ziti-console-lib/src/lib/pages/certificate-authorities/certificate-authorities-page.component.ts new file mode 100644 index 00000000..a6f3bc57 --- /dev/null +++ b/projects/ziti-console-lib/src/lib/pages/certificate-authorities/certificate-authorities-page.component.ts @@ -0,0 +1,114 @@ +/* + Copyright NetFoundry Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import {Component, OnInit} from '@angular/core'; +import {DataTableFilterService} from "../../features/data-table/data-table-filter.service"; +import {CertificateAuthoritiesPageService} from "./certificate-authorities-page.service"; +import {TabNameService} from "../../services/tab-name.service"; +import {ListPageComponent} from "../../shared/list-page-component.class"; +import {ConsoleEventsService} from "../../services/console-events.service"; +import {MatDialog} from "@angular/material/dialog"; +import {ConfirmComponent} from "../../features/confirm/confirm.component"; +import {firstValueFrom} from "rxjs"; + + +@Component({ + selector: 'lib-auth-policies', + templateUrl: './certificate-authorities-page.component.html', + styleUrls: ['./certificate-authorities-page.component.scss'] +}) +export class CertificateAuthoritiesPageComponent extends ListPageComponent implements OnInit { + title = 'Certificate Authorities' + tabs: { url: string, label: string }[] ; + isLoading: boolean; + formDataChanged = false; + + constructor( + override svc: CertificateAuthoritiesPageService, + filterService: DataTableFilterService, + private tabNames: TabNameService, + consoleEvents: ConsoleEventsService, + dialogForm: MatDialog + ) { + super(filterService, svc, consoleEvents, dialogForm); + } + + override ngOnInit() { + this.tabs = this.tabNames.getTabs('authentication'); + this.svc.refreshData = this.refreshData; + super.ngOnInit(); + } + + headerActionClicked(action: string) { + switch (action) { + case 'add': + this.svc.openEditForm(); + break; + case 'edit': + this.svc.openEditForm(); + break; + case 'delete': + const selectedItems = this.rowData.filter((row) => { + return row.selected; + }); + const label = selectedItems.length > 1 ? 'certificate authorities' : 'certificate authority'; + this.openBulkDelete(selectedItems, label); + break; + default: + } + } + + tableAction(event: any) { + switch(event?.action) { + case 'toggleAll': + case 'toggleItem': + this.itemToggled(event.item) + break; + case 'update': + this.svc.openEditForm(event.item?.id); + break; + case 'create': + this.svc.openEditForm(); + break; + case 'delete': + this.deleteItem(event.item) + break; + case 'download-all': + this.downloadAllItems(); + break; + case 'download-selected': + this.svc.downloadItems(this.selectedItems); + break; + default: + break; + } + } + + deleteItem(item: any) { + this.openBulkDelete([item], 'certificate authority'); + } + + closeModal(event: any) { + this.svc.sideModalOpen = false; + if(event?.refresh) { + this.refreshData(); + } + } + + dataChanged(event) { + this.formDataChanged = event; + } +} diff --git a/projects/ziti-console-lib/src/lib/pages/certificate-authorities/certificate-authorities-page.service.ts b/projects/ziti-console-lib/src/lib/pages/certificate-authorities/certificate-authorities-page.service.ts new file mode 100644 index 00000000..7bbfae03 --- /dev/null +++ b/projects/ziti-console-lib/src/lib/pages/certificate-authorities/certificate-authorities-page.service.ts @@ -0,0 +1,196 @@ +/* + Copyright NetFoundry Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import {Inject, Injectable} from '@angular/core'; +import {DataTableFilterService, FilterObj} from "../../features/data-table/data-table-filter.service"; +import _, {isEmpty, unset} from "lodash"; +import moment from "moment"; +import {ListPageServiceClass} from "../../shared/list-page-service.class"; +import { + TableColumnDefaultComponent +} from "../../features/data-table/column-headers/table-column-default/table-column-default.component"; +import {CallbackResults} from "../../features/list-page-features/list-page-form/list-page-form.component"; +import {SchemaService} from "../../services/schema.service"; +import {SETTINGS_SERVICE, SettingsService} from "../../services/settings.service"; +import {CsvDownloadService} from "../../services/csv-download.service"; +import {ExtensionService, SHAREDZ_EXTENSION} from "../../features/extendable/extensions-noop.service"; +import {Service} from "../../models/service"; +import {TableCellNameComponent} from "../../features/data-table/cells/table-cell-name/table-cell-name.component"; +import {Router} from "@angular/router"; +import {ConfirmComponent} from "../../features/confirm/confirm.component"; +import {firstValueFrom} from "rxjs"; +import {MatDialog} from "@angular/material/dialog"; + +@Injectable({ + providedIn: 'root' +}) +export class CertificateAuthoritiesPageService extends ListPageServiceClass { + + private paging = this.DEFAULT_PAGING; + + resourceType = 'cas'; + selectedConfig: any = {}; + modalType = ''; + + override menuItems = [ + {name: 'Edit', action: 'update'}, + {name: 'Delete', action: 'delete'}, + ] + + constructor( + private schemaSvc: SchemaService, + @Inject(SETTINGS_SERVICE) settings: SettingsService, + filterService: DataTableFilterService, + csvDownloadService: CsvDownloadService, + @Inject(SHAREDZ_EXTENSION) extService: ExtensionService, + protected override router: Router, + private dialogForm: MatDialog + ) { + super(settings, filterService, csvDownloadService, extService, router); + } + + initTableColumns(): any { + + const verifiedHeaderComponentParams = { + filterType: 'SELECT', + enableSorting: true, + filterOptions: [ + { label: 'All', value: '' }, + { label: 'Verified', value: true }, + { label: 'Unverified', value: false }, + ] + }; + const createdAtHeaderComponentParams = { + filterType: 'DATETIME', + }; + return [ + { + colId: 'name', + field: 'name', + headerName: 'Name', + headerComponent: TableColumnDefaultComponent, + headerComponentParams: this.headerComponentParams, + cellRenderer: TableCellNameComponent, + cellRendererParams: { pathRoot: this.basePath }, + onCellClicked: (data) => { + if (this.hasSelectedText()) { + return; + } + this.openEditForm(data?.data?.id); + }, + resizable: true, + cellClass: 'nf-cell-vert-align tCol', + sortable: true, + filter: true, + sortColumn: this.sort.bind(this) + }, + { + colId: 'isVerified', + field: 'isVerified', + headerName: 'Verified', + headerComponent: TableColumnDefaultComponent, + headerComponentParams: verifiedHeaderComponentParams, + resizable: true, + cellClass: 'nf-cell-vert-align tCol', + sortable: true, + filter: true, + sortColumn: this.sort.bind(this), + }, + { + colId: 'isAutoCaEnrollmentEnabled', + field: 'isAutoCaEnrollmentEnabled', + headerName: 'Auto Enrollment', + headerComponent: TableColumnDefaultComponent, + resizable: true, + cellClass: 'nf-cell-vert-align tCol', + sortable: true, + filter: true, + sortColumn: this.sort.bind(this), + }, + { + colId: 'isOttCaEnrollmentEnabled', + field: 'isOttCaEnrollmentEnabled', + headerName: 'OTT Auto', + headerComponent: TableColumnDefaultComponent, + resizable: true, + cellClass: 'nf-cell-vert-align tCol', + sortable: true, + filter: true, + sortColumn: this.sort.bind(this), + }, + { + colId: 'isAuthEnabled', + field: 'isAuthEnabled', + headerName: 'Auth Enabled', + headerComponent: TableColumnDefaultComponent, + resizable: true, + cellClass: 'nf-cell-vert-align tCol', + sortable: true, + filter: true, + sortColumn: this.sort.bind(this), + }, + { + colId: 'createdAt', + field: 'createdAt', + headerName: 'Created At', + headerComponent: TableColumnDefaultComponent, + headerComponentParams: createdAtHeaderComponentParams, + valueFormatter: this.createdAtFormatter, + resizable: true, + cellClass: 'nf-cell-vert-align tCol', + } + ]; + } + + getData(filters?: FilterObj[], sort?: any) { + // we can customize filters or sorting here before moving on... + return super.getTableData(this.resourceType, this.paging, filters, sort) + .then((results: any) => { + return this.processData(results); + }); + } + + validate = (formData): Promise => { + return Promise.resolve({ passed: true}); + } + + private processData(results: any) { + if (!isEmpty(results?.data)) { + //pre-process data before rendering + results.data = this.addActionsPerRow(results); + } + return results; + } + + private addActionsPerRow(results: any): any[] { + return results.data.map((row) => { + row.actionList = ['update', 'delete']; + return row; + }); + } + + public openUpdate(item?: any) { + this.modalType = 'cas'; + if (item) { + this.selectedConfig = item; + this.selectedConfig.badges = []; + unset(this.selectedConfig, '_links'); + } else { + this.selectedConfig = new Service(); + } + this.sideModalOpen = true; + } +} diff --git a/projects/ziti-console-lib/src/lib/ziti-console-lib.module.ts b/projects/ziti-console-lib/src/lib/ziti-console-lib.module.ts index b8f8baa4..2ef66694 100644 --- a/projects/ziti-console-lib/src/lib/ziti-console-lib.module.ts +++ b/projects/ziti-console-lib/src/lib/ziti-console-lib.module.ts @@ -113,6 +113,7 @@ import {JwtSignersPageComponent} from "./pages/jwt-signers/jwt-signers-page.comp import {JwtSignerFormComponent} from "./features/projectable-forms/jwt-signer/jwt-signer-form.component"; import {AuthPoliciesPageComponent} from "./pages/auth-policies/auth-policies-page.component"; import {AuthPolicyFormComponent} from "./features/projectable-forms/auth-policy/auth-policy-form.component"; +import {CertificateAuthoritiesPageComponent} from "./pages/certificate-authorities/certificate-authorities-page.component"; import {PreviewSelectionsComponent} from "./features/preview-selections/preview-selections.component"; export function playerFactory() { @@ -198,7 +199,8 @@ export function playerFactory() { JwtSignerFormComponent, AuthPoliciesPageComponent, AuthPolicyFormComponent, - PreviewSelectionsComponent + PreviewSelectionsComponent, + CertificateAuthoritiesPageComponent ], imports: [ CommonModule, diff --git a/projects/ziti-console-lib/src/public-api.ts b/projects/ziti-console-lib/src/public-api.ts index e3595843..b1d8ee84 100644 --- a/projects/ziti-console-lib/src/public-api.ts +++ b/projects/ziti-console-lib/src/public-api.ts @@ -24,6 +24,8 @@ export * from './lib/pages/jwt-signers/jwt-signers-page.component'; export * from './lib/pages/jwt-signers/jwt-signers-page.service'; export * from './lib/pages/auth-policies/auth-policies-page.component'; export * from './lib/pages/auth-policies/auth-policies-page.service'; +export * from './lib/pages/certificate-authorities/certificate-authorities-page.component'; +export * from './lib/pages/certificate-authorities/certificate-authorities-page.service'; export * from './lib/services/login-service.class'; export * from './lib/services/noop-login.service'; export * from './lib/services/settings-service.class'; From 499e3ce2dd6194618672b48ed0ca9074e335db7f Mon Sep 17 00:00:00 2001 From: Ryan Galletto Date: Mon, 27 Jan 2025 08:27:58 -0500 Subject: [PATCH 2/2] New Certificate Authorities Edit Form * Replaces legacy edit form and verify modal with new angular components --- package-lock.json | 6 +- .../src/app/app-routing.module.ts | 21 +- .../src/app/app.component.scss | 3 +- .../src/lib/assets/fonts/icomoon.eot | Bin 0 -> 50884 bytes .../src/lib/assets/fonts/icomoon.svg | 118 +++++ .../src/lib/assets/fonts/icomoon.ttf | Bin 0 -> 50720 bytes .../src/lib/assets/fonts/icomoon.woff | Bin 0 -> 50796 bytes .../src/lib/assets/fonts/icomoon.woff2 | Bin 0 -> 24596 bytes .../src/lib/assets/styles/icons.css | 13 + .../auth-policy-form.component.html | 2 +- .../certificate-authority-form.component.html | 269 +++++++++++ .../certificate-authority-form.component.scss | 187 ++++++++ .../certificate-authority-form.component.ts | 440 ++++++++++++++++++ .../certificate-authority-form.service.ts | 113 +++++ .../verify-certificate.component.html | 65 +++ .../verify-certificate.component.scss | 138 ++++++ .../verify-certificate.component.ts | 245 ++++++++++ .../verify-certificate.service.ts | 57 +++ .../form-field-container.component.html | 25 + .../form-field-container.component.ts | 14 + .../form-header/form-header.component.html | 17 +- .../form-header/form-header.component.scss | 7 +- .../form-header/form-header.component.ts | 2 + .../side-banner/side-banner.component.scss | 2 +- .../side-toolbar/side-toolbar.component.scss | 2 +- .../src/lib/models/certificate-authority.ts | 13 + .../certificate-authorities-page.component.ts | 5 +- .../certificate-authorities-page.service.ts | 20 +- .../src/lib/services/validation.service.ts | 17 +- .../services/ziti-controller-data.service.ts | 12 +- .../src/lib/services/ziti-data.service.ts | 18 +- .../src/lib/shared-assets/styles/global.scss | 150 +++++- .../src/lib/ziti-console-lib.module.ts | 8 +- projects/ziti-console-lib/src/public-api.ts | 3 + release-notes.md | 1 - 35 files changed, 1949 insertions(+), 44 deletions(-) create mode 100644 projects/ziti-console-lib/src/lib/assets/fonts/icomoon.eot create mode 100644 projects/ziti-console-lib/src/lib/assets/fonts/icomoon.svg create mode 100644 projects/ziti-console-lib/src/lib/assets/fonts/icomoon.ttf create mode 100644 projects/ziti-console-lib/src/lib/assets/fonts/icomoon.woff create mode 100644 projects/ziti-console-lib/src/lib/assets/fonts/icomoon.woff2 create mode 100644 projects/ziti-console-lib/src/lib/features/projectable-forms/certificate-authority/certificate-authority-form.component.html create mode 100644 projects/ziti-console-lib/src/lib/features/projectable-forms/certificate-authority/certificate-authority-form.component.scss create mode 100644 projects/ziti-console-lib/src/lib/features/projectable-forms/certificate-authority/certificate-authority-form.component.ts create mode 100644 projects/ziti-console-lib/src/lib/features/projectable-forms/certificate-authority/certificate-authority-form.service.ts create mode 100644 projects/ziti-console-lib/src/lib/features/projectable-forms/certificate-authority/verify-certificate/verify-certificate.component.html create mode 100644 projects/ziti-console-lib/src/lib/features/projectable-forms/certificate-authority/verify-certificate/verify-certificate.component.scss create mode 100644 projects/ziti-console-lib/src/lib/features/projectable-forms/certificate-authority/verify-certificate/verify-certificate.component.ts create mode 100644 projects/ziti-console-lib/src/lib/features/projectable-forms/certificate-authority/verify-certificate/verify-certificate.service.ts create mode 100644 projects/ziti-console-lib/src/lib/models/certificate-authority.ts diff --git a/package-lock.json b/package-lock.json index b33b7e7e..6495ec5d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "io.netfoundry.zac", - "version": "3.6.3", + "version": "3.7.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "io.netfoundry.zac", - "version": "3.6.3", + "version": "3.7.1", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -93,7 +93,7 @@ }, "dist/ziti-console-lib": { "name": "@openziti/ziti-console-lib", - "version": "0.6.5", + "version": "0.0.0-watch+1737585178432", "license": "Apache-2.0", "dependencies": { "tslib": "^2.3.0" diff --git a/projects/app-ziti-console/src/app/app-routing.module.ts b/projects/app-ziti-console/src/app/app-routing.module.ts index 595b45e5..1c451522 100644 --- a/projects/app-ziti-console/src/app/app-routing.module.ts +++ b/projects/app-ziti-console/src/app/app-routing.module.ts @@ -43,7 +43,10 @@ import { JwtSignersPageComponent, JwtSignerFormComponent, AuthPoliciesPageComponent, - AuthPolicyFormComponent + AuthPolicyFormComponent, + CertificateAuthoritiesPageComponent, + CertificateAuthorityFormComponent, + VerifyCertificateComponent } from "ziti-console-lib"; import {environment} from "./environments/environment"; import {URLS} from "./app-urls.constants"; @@ -250,8 +253,22 @@ const routes: Routes = [ }, { path: 'certificate-authorities', - component: ZacWrapperComponent, + component: CertificateAuthoritiesPageComponent, + canActivate: mapToCanActivate([AuthenticationGuard]), + runGuardsAndResolvers: 'always', + }, + { + path: 'certificate-authorities/:id', + component: CertificateAuthorityFormComponent, canActivate: mapToCanActivate([AuthenticationGuard]), + canDeactivate: [DeactivateGuardService], + runGuardsAndResolvers: 'always', + }, + { + path: 'certificate-authorities/:id/verify', + component: VerifyCertificateComponent, + canActivate: mapToCanActivate([AuthenticationGuard]), + canDeactivate: [DeactivateGuardService], runGuardsAndResolvers: 'always', }, { diff --git a/projects/app-ziti-console/src/app/app.component.scss b/projects/app-ziti-console/src/app/app.component.scss index dcca6638..dfe93be5 100644 --- a/projects/app-ziti-console/src/app/app.component.scss +++ b/projects/app-ziti-console/src/app/app.component.scss @@ -2,6 +2,7 @@ .main { display: flex; background-color: var(--navigation); + height: 100%; .modals { position: absolute; @@ -16,7 +17,7 @@ display: flex; margin: 0; padding: 0; - min-height: 100vh; + min-height: 100%; max-width: 23.75rem; background-color: var(--shaded); box-shadow: inset 0rem 0.25rem 1rem 0rem rgba(0, 0, 0, 0.08); diff --git a/projects/ziti-console-lib/src/lib/assets/fonts/icomoon.eot b/projects/ziti-console-lib/src/lib/assets/fonts/icomoon.eot new file mode 100644 index 0000000000000000000000000000000000000000..fd0ecee5016adc3f9fed9d009bcba45da34d71f6 GIT binary patch literal 50884 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 + + +Generated by IcoMoon + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/projects/ziti-console-lib/src/lib/assets/fonts/icomoon.ttf b/projects/ziti-console-lib/src/lib/assets/fonts/icomoon.ttf new file mode 100644 index 0000000000000000000000000000000000000000..fd44bd8d1dbb5136d1f524c3b1e5fa67f630835f GIT binary patch literal 50720 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 literal 0 HcmV?d00001 diff --git a/projects/ziti-console-lib/src/lib/assets/fonts/icomoon.woff b/projects/ziti-console-lib/src/lib/assets/fonts/icomoon.woff new file mode 100644 index 0000000000000000000000000000000000000000..229c577ba13bca4244f3e9aada44d263efe29cd3 GIT binary patch literal 50796 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 S0d_bKfH7iou3eIMm;WbUG?zL6 literal 0 HcmV?d00001 diff --git a/projects/ziti-console-lib/src/lib/assets/fonts/icomoon.woff2 b/projects/ziti-console-lib/src/lib/assets/fonts/icomoon.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..56350bf2c32962827c5d7462f50d0cab58b1b6ad GIT binary patch literal 24596 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 - + + + +
+ diff --git a/projects/ziti-console-lib/src/lib/features/projectable-forms/certificate-authority/certificate-authority-form.component.scss b/projects/ziti-console-lib/src/lib/features/projectable-forms/certificate-authority/certificate-authority-form.component.scss new file mode 100644 index 00000000..58e8be8a --- /dev/null +++ b/projects/ziti-console-lib/src/lib/features/projectable-forms/certificate-authority/certificate-authority-form.component.scss @@ -0,0 +1,187 @@ +.form-group-column { + &.three-fifths { + min-width: 31.25rem; + } +} + +.jwt-signer-form-container { + display: flex; + flex-direction: column; + height: 100%; + width: 100%; + align-items: center; + gap: var(--gapXL); + + .select-file-button { + padding-left: var(--paddingMedium); + padding-right: var(--paddingMedium); + height: 1.5625rem; + width: fit-content; + white-space: nowrap; + display: flex; + align-items: center; + justify-content: center; + font-weight: 600; + font-size: 0.875rem; + background: var(--primary); + border-style: solid; + border-width: 0.0625rem; + border-color: var(--stroke); + color: var(--white); + cursor: pointer; + border-radius: var(--inputBorderRadius); + gap: var(--marginMedium); + margin-top: -0.3125rem; + + &:hover { + filter: brightness(.8); + } + &:active { + filter: grayscale(1); + transform: translateY(0.0625rem); + } + + .spinner { + display: inline-block; + width: 0.5rem; + height: 0.5rem; + border-radius: 50%; + background: transparent; + border-top: 0.125rem solid white; + border-right: 0.125rem solid white; + border-bottom: 0.125rem solid transparent; + border-left: 0.125rem solid transparent; + -webkit-animation: loading 0.5s infinite linear; + animation: loading 0.5s infinite linear; + } + } + + .select-file-label-container { + gap: var(--marginMedium); + } + + .updb-input-options { + margin-top: var(--marginSmall); + background-color: var(--formGroup); + padding: var(--paddingMedium); + border-radius: var(--inputBorderRadius); + + .form-field-title { + color: var(--offWhite); + } + } +} + +::ng-deep .jwt-signer-form-container { + select, + input { + &:disabled { + opacity: 0.75 !important; + cursor: text; + background-color: var(--stroke) !important; + } + } +} + +::ng-deep .api-data-no-wrap{ + .jse-text-mode { + width: 100%; + .cm-editor { + width: 100%; + .cm-scroller { + width: 100%; + .cm-content { + width: 100%; + overflow: auto; + .ͼr { + white-space: nowrap; + } + } + } + } + } +} + +.radio-group-container { + display: flex; + gap: var(--marginLarge); + + &:focus { + .radio-button-container { + .radio-button-circle { + border-color: var(--primaryColor); + } + } + } + + .radio-button-container { + display: flex; + flex-direction: row; + align-items: center; + background-color: var(--formGroup); + border-radius: var(--inputBorderRadius); + width: 100%; + padding-left: var(--paddingMedium); + padding-right: var(--paddingMedium); + padding-top: var(--paddingLarge); + padding-bottom: var(--paddingLarge); + cursor: pointer; + gap: var(--marginMedium); + + .radio-button-circle { + display: flex; + width: 1.3125rem; + height: 1.3125rem; + border-radius: 1.3125rem; + border-width: 0.125rem; + border-style: solid; + border-color: var(--offWhite); + align-items: center; + justify-content: center; + background-color: var(--offWhite); + + .radio-button-inner-circle { + display: none; + width: 0.9375rem; + height: 0.9375rem; + border-radius: 0.9375rem; + align-items: center; + justify-content: center; + background-color: var(--primaryColor); + } + } + + &.selected { + .radio-button-circle { + .radio-button-inner-circle { + display: flex; + } + } + } + + &:active { + .radio-button-circle { + .radio-button-inner-circle { + display: flex; + background-color: var(--menu); + } + } + } + + .radio-button-label { + color: var(--offWhite); + font-size: 0.875rem; + font-weight: 600; + } + } +} + +.allowed-signers-container { + background-color: var(--formGroup); + padding: var(--paddingMedium); + border-radius: var(--inputBorderRadius); + + .form-field-title { + color: var(--offWhite); + } +} \ No newline at end of file diff --git a/projects/ziti-console-lib/src/lib/features/projectable-forms/certificate-authority/certificate-authority-form.component.ts b/projects/ziti-console-lib/src/lib/features/projectable-forms/certificate-authority/certificate-authority-form.component.ts new file mode 100644 index 00000000..b322abfd --- /dev/null +++ b/projects/ziti-console-lib/src/lib/features/projectable-forms/certificate-authority/certificate-authority-form.component.ts @@ -0,0 +1,440 @@ +/* + Copyright NetFoundry Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import { + Component, ElementRef, + EventEmitter, Inject, + Input, + OnDestroy, + OnInit, Output, + ViewChild, +} from '@angular/core'; +import {CertificateAuthorityFormService} from "./certificate-authority-form.service"; +import {SchemaService} from "../../../services/schema.service"; +import {KEY_CODES, ProjectableForm} from "../projectable-form.class"; +import {GrowlerService} from "../../messaging/growler.service"; +import {ExtensionService, SHAREDZ_EXTENSION} from "../../extendable/extensions-noop.service"; + +import {cloneDeep, defer, delay, forOwn, keys, invert, isEmpty, isNil, unset, sortedUniq, debounce} from 'lodash'; +import {GrowlerModel} from "../../messaging/growler.model"; +import {SETTINGS_SERVICE, SettingsService} from "../../../services/settings.service"; +import {ZITI_DATA_SERVICE, ZitiDataService} from "../../../services/ziti-data.service"; +import {ActivatedRoute, Router} from "@angular/router"; +import {Location} from "@angular/common"; +import {ValidationService} from "../../../services/validation.service"; +import {CertificateAuthority} from "../../../models/certificate-authority"; + +@Component({ + selector: 'lib-certificate-authority', + templateUrl: './certificate-authority-form.component.html', + styleUrls: ['./certificate-authority-form.component.scss'] +}) +export class CertificateAuthorityFormComponent extends ProjectableForm implements OnInit, OnDestroy { + + @Input() override formData: any = new CertificateAuthority(); + @Input() override errors: any = {}; + @Output() close: EventEmitter = new EventEmitter(); + + _externalIdClaim = false; + + formView = 'simple'; + options: any[] = []; + isEditing = !isEmpty(this.formData.id); + formDataInvalid = false; + editMode = false; + items: any = []; + settings: any = {}; + fileSelectOpening = false; + identityRoleAttributes = []; + override entityType = 'cas'; + override entityClass = CertificateAuthority; + + locations = ['COMMON_NAME', 'SAN_URI', 'SAN_EMAIL']; + matchers = ['ALL', 'PREFIX', 'SUFFIX', 'SCHEME']; + parsers = ['NONE', 'SPLIT']; + + @ViewChild('fileSelect') filterInput: ElementRef; + + constructor( + public svc: CertificateAuthorityFormService, + private schemaSvc: SchemaService, + growlerService: GrowlerService, + @Inject(SHAREDZ_EXTENSION) extService: ExtensionService, + @Inject(SETTINGS_SERVICE) public settingsService: SettingsService, + @Inject(ZITI_DATA_SERVICE) override zitiService: ZitiDataService, + protected override router: Router, + protected override route: ActivatedRoute, + location: Location, + private validationService: ValidationService + ) { + super(growlerService, extService, zitiService, router, route, location); + } + + override ngOnInit(): void { + super.ngOnInit(); + this.svc.getIdentityRoleAttributes().then((results) => { + this.identityRoleAttributes = results?.data || []; + }); + this.settingsService.settingsChange.subscribe((results:any) => { + this.settings = results; + }); + } + + protected override entityUpdated() { + super.entityUpdated(); + } + + ngOnDestroy(): void { + this.clearForm(); + } + + headerActionRequested(event) { + switch(event.name) { + case 'save': + this.save(event); + break; + case 'close': + this.returnToListPage(); + break; + case 'toggle-view': + this.formView = event.data; + break; + } + } + + externalIdClaimChanged() { + if (this.externalIdClaim && !this.formData.externalIdClaim) { + this.formData.externalIdClaim = { + location: '', + matcher: '', + parser: '', + index: 0, + matcherCriteria: '', + parserCriteria: '' + } + } + } + + override clear() { + this.formData.configTypeId = ''; + this.clearForm(); + } + + clearForm() { + this.items.forEach((item: any) => { + if (item?.component) item.component.destroy(); + }); + this.errors = {}; + this.items = []; + this.formData = new CertificateAuthority(); + if (this.subscription) this.subscription.unsubscribe(); + } + + async save(event?: any) { + if(!this.validate()) { + return; + } + const tagVals = this.getTagValues(); + if (!isEmpty(tagVals)) { + forOwn(tagVals, (value, key) => { + this.formData.tags[key] = value; + }); + } + const apiData = this.apiData; + apiData.id = this.formData.id; + this.isLoading = true; + this.svc.save(apiData).then((result) => { + if (this.isModal) { + this.closeModal(true, true); + return; + } + this.initData = this.formData; + this._dataChange = false; + this.returnToListPage(); + }).finally(() => { + this.isLoading = false; + }); + } + + validate() { + this.errors = {}; + const labels = []; + const growlers = []; + if (isEmpty(this.formData.name)) { + this.errors.name = true; + labels.push('Name'); + } + if (this.externalIdClaim) { + if (isEmpty(this.claimLocation)) { + this.errors.claimLocation = true; + labels.push('Location'); + } + if (isEmpty(this.parser)) { + this.errors.parser = true; + labels.push('Parser'); + } + if (isEmpty(this.matcher)) { + this.errors.matcher = true; + labels.push('Matcher'); + } + if (isEmpty(this.parserCriteria)) { + this.errors.parserCriteria = true; + labels.push('Parser Criteria'); + } + if (isEmpty(this.matcherCriteria)) { + this.errors.matcherCriteria = true; + labels.push('Matcher Criteria'); + } + if (isNaN(this.index) || this.index < 0) { + this.errors.index = true; + labels.push('Index'); + } + } + if (!this.validationService.isValidPEM(this.formData.certPem)) { + this.errors.certPem = true; + labels.push('Cert PEM'); + } + if (!isEmpty(this.errors)) { + let errorLabels = ''; + labels.forEach((label, index) => { + errorLabels += `
  • ${label}
  • `; + }); + errorLabels = `
      ${errorLabels}
    `; + growlers.push(new GrowlerModel( + 'error', + 'Invalid', + `Missing Form Data`, + `Please enter a value for the highlighted fields: ${errorLabels}`, + )); + } + if (!isEmpty(growlers)) { + growlers.forEach((growlerData) => { + this.growlerService.show(growlerData); + }); + return isEmpty(this.errors); + } + + growlers.forEach((growlerData) => { + this.growlerService.show(growlerData); + }); + return isEmpty(this.errors); + } + + get apiCallURL() { + return this.settings.selectedEdgeController + '/edge/management/v1/cas' + (this.formData.id ? `/${this.formData.id}` : ''); + } + + get apiData(): any { + const data: any = { + name: this.formData.name || '', + isAutoCaEnrollmentEnabled: this.formData.isAutoCaEnrollmentEnabled, + isOttCaEnrollmentEnabled: this.formData.isOttCaEnrollmentEnabled, + identityRoles: this.formData.identityRoles || [], + identityNameFormat: this.formData.identityNameFormat, + isAuthEnabled: this.formData.isAuthEnabled, + certPem: this.formData.certPem, + + tags: this.formData.tags || {} + }; + if (this.externalIdClaim) { + data.externalIdClaim = this.formData.externalIdClaim; + } + this._apiData = data; + return this._apiData; + } + + _apiData: any = {}; + set apiData(data) { + this._apiData = data; + } + + dataChanged(event) { + this._apiData = cloneDeep(this.apiData); + } + + get externalIdClaim() { + if (this.formData.externalIdClaim) { + this._externalIdClaim = true; + } + return this._externalIdClaim; + } + + set externalIdClaim(val) { + if (!val) { + this.formData.externalIdClaim = undefined; + } + this._externalIdClaim = val; + } + + toggleSwitch(prop) { + if (prop === 'externalIdClaim') { + this.externalIdClaim = !this.externalIdClaim; + } + this.formData[prop] = !this.formData[prop]; + } + + openFileSelect(event: any) { + this.filterInput.nativeElement.click(); + this.fileSelectOpening = true; + delay(() => { + this.fileSelectOpening = false; + }, 1000); + } + + selectPemFile(event: any) { + console.log(event); + const file: File = event?.target?.files[0]; + + if (file) { + const fileReader = new FileReader(); + fileReader.onload = (fileLoadedEvent) => { + const textFromSelectedFile: any = fileLoadedEvent.target?.result; + if (!this.validationService.isValidPEM(textFromSelectedFile?.trim())) { + this.errors.certPem = true; + const growlerData = new GrowlerModel( + 'error', + 'Invalid', + `Cert PEM Invalid`, + `The file selected for the Cert PEM field is invalid. Please check your input and try again.`, + ); + this.growlerService.show(growlerData); + this.formData.certPem = 'Invalid PEM. Please select or enter a valid PEM certificate.'; + } else { + unset(this.errors, 'certPem'); + this.formData.certPem = textFromSelectedFile; + } + }; + fileReader.readAsText(file, "UTF-8"); + } + } + + apiActionRequested(action) { + switch (action.id) { + case 'cli': + this.copyCLICommand(); + break; + case 'curl': + this.copyCURLCommand(); + break; + } + } + + copyCLICommand() { + let command = `ziti edge ${this.formData.id ? 'update' : 'create'} ca ${this.formData.id ? `'${this.formData.id}'` : ''} ${this.formData.id ? '--name' : ''} '${this.formData.name}' ${this.formData.id ? '' : this.formData.certPem} --identity-name-format '${this.formData.identityNameFormat}' --auth '${this.formData.isAuthEnabled}' --auth '${this.formData.isAuthEnabled}' --autoca '${this.formData.isAutoCaEnrollmentEnabled}' --ottca '${this.formData.isOttCaEnrollmentEnabled}'`; + if (this.externalIdClaim) { + command += ` --location '${this.formData.externalIdClaim.location}' --matcher '${this.formData.externalIdClaim.matcher}' --parser '${this.formData.externalIdClaim.parser}' --index '${this.formData.externalIdClaim.index}' --matcher-criteria '${this.formData.externalIdClaim.matcherCriteria}' --parser-criteria '${this.formData.externalIdClaim.parserCriteria}'` + } + + navigator.clipboard.writeText(command); + const growlerData = new GrowlerModel( + 'success', + 'Success', + `Text Copied`, + `CLI command copied to clipboard`, + ); + this.growlerService.show(growlerData); + } + + copyCURLCommand() { + const command = `curl '${this.apiCallURL}' \\ + ${this.formData.id ? '--request PATCH \\' : '\\'} + -H 'accept: application/json' \\ + -H 'content-type: application/json' \\ + -H 'zt-session: ${this.settings.session.id}' \\ + --data-raw '${JSON.stringify(this.apiData)}'`; + + navigator.clipboard.writeText(command); + const growlerData = new GrowlerModel( + 'success', + 'Success', + `Text Copied`, + `CURL command copied to clipboard`, + ); + this.growlerService.show(growlerData); + } + + verifyCertificate(event) { + event.stopPropagation(); + event.preventDefault(); + this.router?.navigateByUrl(`${this.basePath}/${this.formData.id}/verify`); + } + + get claimLocation() { + return this.formData.externalIdClaim?.location; + } + + set claimLocation(loc) { + if (!this.formData.externalIdClaim) { + return; + } + this.formData.externalIdClaim.location = loc; + } + + get matcher() { + return this.formData.externalIdClaim?.matcher; + } + + set matcher(matcher) { + if (!this.formData.externalIdClaim) { + return; + } + this.formData.externalIdClaim.matcher = matcher; + } + + get parser() { + return this.formData.externalIdClaim?.parser; + } + + set parser(parser) { + if (!this.formData.externalIdClaim) { + return; + } + this.formData.externalIdClaim.parser = parser; + } + + get index() { + return this.formData.externalIdClaim?.index; + } + + set index(index) { + if (!this.formData.externalIdClaim) { + return; + } + this.formData.externalIdClaim.index = index; + } + + get matcherCriteria() { + return this.formData.externalIdClaim?.matcherCriteria; + } + + set matcherCriteria(matcherCriteria) { + if (!this.formData.externalIdClaim) { + return; + } + this.formData.externalIdClaim.matcherCriteria = matcherCriteria; + } + + get parserCriteria() { + return this.formData.externalIdClaim?.parserCriteria; + } + + set parserCriteria(parserCriteria) { + if (!this.formData.externalIdClaim) { + return; + } + this.formData.externalIdClaim.parserCriteria = parserCriteria; + } +} diff --git a/projects/ziti-console-lib/src/lib/features/projectable-forms/certificate-authority/certificate-authority-form.service.ts b/projects/ziti-console-lib/src/lib/features/projectable-forms/certificate-authority/certificate-authority-form.service.ts new file mode 100644 index 00000000..2fc7f5ba --- /dev/null +++ b/projects/ziti-console-lib/src/lib/features/projectable-forms/certificate-authority/certificate-authority-form.service.ts @@ -0,0 +1,113 @@ +import {Injectable, Inject} from '@angular/core'; +import {ZITI_DATA_SERVICE, ZitiDataService} from "../../../services/ziti-data.service"; +import {cloneDeep, defer, invert, isBoolean, isEmpty, isNil, keys} from "lodash"; +import {GrowlerModel} from "../../messaging/growler.model"; +import {GrowlerService} from "../../messaging/growler.service"; +import {ExtensionService, SHAREDZ_EXTENSION} from "../../extendable/extensions-noop.service"; +import {ValidationService} from "../../../services/validation.service"; +import {AuthPolicy} from "../../../models/auth-policy"; +import {CertificateAuthority} from "../../../models/certificate-authority"; + +@Injectable({ + providedIn: 'root' +}) +export class CertificateAuthorityFormService { + + items: any[] = []; + errors: any[] = []; + saveDisabled = false; + + jwtSigners = []; + jwtSignerNamedAttributes = []; + jwtSignerNamedAttributesMap = {}; + jwtSignersLoading = false; + + selectedSecondaryJwtSigner; + filteredJwtSigners; + + paging = { + filter: "", + noSearch: true, + order: "asc", + page: 1, + searchOn: "name", + sort: "name", + total: 100 + } + + constructor( + @Inject(ZITI_DATA_SERVICE) private dataService: ZitiDataService, + @Inject(SHAREDZ_EXTENSION)private extService: ExtensionService, + private growlerService: GrowlerService, + private validationService: ValidationService + ) { + } + + save(formData) { + const isUpdate = !isEmpty(formData.id); + const data: any = this.getAuthPolicyDataModel(formData, isUpdate); + let prom; + if (isUpdate) { + prom = this.dataService.put('cas', data, formData.id, true); + } else { + prom = this.dataService.post('cas', data, true); + } + + return prom.then(async (result: any) => { + const id = isUpdate ? formData.id : (result?.data?.id || result?.id); + let config = await this.dataService.getSubdata('cas', id, '').then((svcData) => { + return svcData.data; + }); + return this.extService.formDataSaved(config).then((formSavedResult: any) => { + if (!formSavedResult) { + return config; + } + const growlerData = new GrowlerModel( + 'success', + 'Success', + `Certificate Authority ${isUpdate ? 'Updated' : 'Created'}`, + `Successfully ${isUpdate ? 'updated' : 'created'} Certificate Authority: ${formData.name}`, + ); + this.growlerService.show(growlerData); + return config; + }).catch((result) => { + return false; + }); + }).catch((resp) => { + let errorMessage; + if (resp?.error?.error?.cause?.message) { + errorMessage = resp?.error?.error?.cause?.message; + } else if (resp?.error?.error?.cause?.reason) { + errorMessage = resp?.error?.error?.cause?.reason; + }else if (resp?.error?.message) { + errorMessage = resp?.error?.message; + } else { + errorMessage = 'An unknown error occurred'; + } + const growlerData = new GrowlerModel( + 'error', + 'Error', + `Error Creating Certificate Authority`, + errorMessage, + ); + this.growlerService.show(growlerData); + throw resp; + }) + } + + getIdentityRoleAttributes() { + return this.dataService.get('identity-role-attributes', {}, []); + } + + getAuthPolicyDataModel(formData, isUpdate) { + const saveModel = new CertificateAuthority(); + const modelProperties = keys(saveModel); + modelProperties.forEach((prop) => { + switch(prop) { + default: + saveModel[prop] = formData[prop]; + } + }); + return saveModel; + } +} diff --git a/projects/ziti-console-lib/src/lib/features/projectable-forms/certificate-authority/verify-certificate/verify-certificate.component.html b/projects/ziti-console-lib/src/lib/features/projectable-forms/certificate-authority/verify-certificate/verify-certificate.component.html new file mode 100644 index 00000000..80b7e3a4 --- /dev/null +++ b/projects/ziti-console-lib/src/lib/features/projectable-forms/certificate-authority/verify-certificate/verify-certificate.component.html @@ -0,0 +1,65 @@ +
    + +
    +
    +
    + +
      +
    • Generate a certificate with the common name CN=XeoiWd16J
    • +
    • Upload the generated cert, or copy & paste it using the text field below
    • +
    • Click the "Verify" button to submit certificate for verification
    • +
    +
    + +
    + {{formData.verificationToken}} +
    +
    +
    + + {{certErrorMessage}} +
    +
    +
    +
    + Enter PEM +
    + + Select File +
    +
    + +
    + +
    +
    +
    +
    +
    Oops, no get me out of here
    +
    Verify
    +
    +
    +
    +
    +
    + diff --git a/projects/ziti-console-lib/src/lib/features/projectable-forms/certificate-authority/verify-certificate/verify-certificate.component.scss b/projects/ziti-console-lib/src/lib/features/projectable-forms/certificate-authority/verify-certificate/verify-certificate.component.scss new file mode 100644 index 00000000..7c796f48 --- /dev/null +++ b/projects/ziti-console-lib/src/lib/features/projectable-forms/certificate-authority/verify-certificate/verify-certificate.component.scss @@ -0,0 +1,138 @@ +::ng-deep .verify-certificate-container lib-form-header .form-header-container { + max-width: 50rem; +} + +.verify-certificate-container { + display: flex; + flex-direction: column; + height: 100%; + width: 100%; + align-items: center; + gap: var(--gapXL); + + .projectable-form-main-column { + max-width: 50rem; + } + + .copy-token-container { + display: flex; + flex-direction: row; + justify-content: flex-start; + align-items: center; + cursor: pointer; + background-color: var(--stroke); + border-radius: var(--inputBorderRadius); + transition: all .2s; + + .copy-icon { + filter: grayscale(1); + } + + &:hover { + .copy-token-button { + transform: scale(1.02); + } + .copy-icon { + transform: scale(1.02); + filter: none; + } + } + + .copy-token-button { + cursor: pointer; + align-items: center; + margin-left: var(--marginMedium); + display: flex; + } + } + + .instructions-list { + margin: 0; + padding-left: 1rem; + display: flex; + flex-direction: column; + gap: .4rem; + font-size: .9rem; + } + + .select-file-button { + padding-left: var(--paddingMedium); + padding-right: var(--paddingMedium); + height: 1.5625rem; + width: fit-content; + white-space: nowrap; + display: flex; + align-items: center; + justify-content: center; + font-weight: 600; + font-size: 0.875rem; + background: var(--primary); + border-style: solid; + border-width: 0.0625rem; + border-color: var(--stroke); + color: var(--white); + cursor: pointer; + border-radius: var(--inputBorderRadius); + gap: var(--marginMedium); + margin-top: -0.3125rem; + + &:hover { + filter: brightness(.8); + } + &:active { + filter: grayscale(1); + transform: translateY(0.0625rem); + } + + .spinner { + display: inline-block; + width: 0.5rem; + height: 0.5rem; + border-radius: 50%; + background: transparent; + border-top: 0.125rem solid white; + border-right: 0.125rem solid white; + border-bottom: 0.125rem solid transparent; + border-left: 0.125rem solid transparent; + -webkit-animation: loading 0.5s infinite linear; + animation: loading 0.5s infinite linear; + } + } + + .select-file-label-container { + gap: var(--marginMedium); + } + + .cert-error-text { + height: .7rem; + } + + .save-button { + display: flex; + align-items: center; + justify-content: center; + font-weight: 600; + font-size: 0.875rem; + background: var(--primary); + padding: 0.4375rem; + border-radius: var(--inputBorderRadius); + color: var(--white); + cursor: pointer; + box-shadow: 0 0.1875rem 0.5625rem 0 var(--primaryColorOpaque); + } +} + +::ng-deep .verify-certificate-container { + select, + input { + &:disabled { + opacity: 0.75 !important; + cursor: text; + background-color: var(--stroke) !important; + } + } +} + +::ng-deep .verify-certificate-wrapper lib-form-header .form-header-container { + max-width: 50rem; +} diff --git a/projects/ziti-console-lib/src/lib/features/projectable-forms/certificate-authority/verify-certificate/verify-certificate.component.ts b/projects/ziti-console-lib/src/lib/features/projectable-forms/certificate-authority/verify-certificate/verify-certificate.component.ts new file mode 100644 index 00000000..03fbb6ad --- /dev/null +++ b/projects/ziti-console-lib/src/lib/features/projectable-forms/certificate-authority/verify-certificate/verify-certificate.component.ts @@ -0,0 +1,245 @@ +/* + Copyright NetFoundry Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import { + Component, ElementRef, + EventEmitter, Inject, + Input, + OnDestroy, + OnInit, Output, + ViewChild, +} from '@angular/core'; +import {VerifyCertificateService} from "./verify-certificate.service"; +import {SchemaService} from "../../../../services/schema.service"; +import {KEY_CODES, ProjectableForm} from "../../projectable-form.class"; +import {GrowlerService} from "../../../messaging/growler.service"; +import {ExtensionService, SHAREDZ_EXTENSION} from "../../../extendable/extensions-noop.service"; + +import {cloneDeep, defer, delay, forOwn, keys, invert, isEmpty, isNil, unset, sortedUniq, debounce} from 'lodash'; +import {GrowlerModel} from "../../../messaging/growler.model"; +import {SETTINGS_SERVICE, SettingsService} from "../../../../services/settings.service"; +import {ZITI_DATA_SERVICE, ZitiDataService} from "../../../../services/ziti-data.service"; +import {ActivatedRoute, Router} from "@angular/router"; +import {Location} from "@angular/common"; +import {ValidationService} from "../../../../services/validation.service"; +import {CertificateAuthority} from "../../../../models/certificate-authority"; + +@Component({ + selector: 'lib-certificate-authority', + templateUrl: './verify-certificate.component.html', + styleUrls: ['./verify-certificate.component.scss'] +}) +export class VerifyCertificateComponent extends ProjectableForm implements OnInit, OnDestroy { + + @Input() override formData: any = new CertificateAuthority(); + @Input() override errors: any = {}; + @Output() close: EventEmitter = new EventEmitter(); + + _externalIdClaim = false; + + formView = 'simple'; + options: any[] = []; + isEditing = !isEmpty(this.formData.id); + formDataInvalid = false; + editMode = false; + items: any = []; + settings: any = {}; + fileSelectOpening = false; + identityRoleAttributes = []; + override entityType = 'cas'; + override entityClass = CertificateAuthority; + + locations = ['COMMON_NAME', 'SAN_URI', 'SAN_EMAIL']; + matchers = ['ALL', 'PREFIX', 'SUFFIX', 'SCHEME']; + parsers = ['NONE', 'SPLIT']; + + certificate = ''; + certErrorMessage = ''; + + @ViewChild('fileSelect') filterInput: ElementRef; + + constructor( + public svc: VerifyCertificateService, + private schemaSvc: SchemaService, + growlerService: GrowlerService, + @Inject(SHAREDZ_EXTENSION) extService: ExtensionService, + @Inject(SETTINGS_SERVICE) public settingsService: SettingsService, + @Inject(ZITI_DATA_SERVICE) override zitiService: ZitiDataService, + protected override router: Router, + protected override route: ActivatedRoute, + location: Location, + private validationService: ValidationService + ) { + super(growlerService, extService, zitiService, router, route, location); + } + + override ngOnInit(): void { + super.ngOnInit(); + this.settingsService.settingsChange.subscribe((results:any) => { + this.settings = results; + }); + } + + protected override entityUpdated() { + super.entityUpdated(); + } + + ngOnDestroy(): void { + this.clearForm(); + } + + headerActionRequested(event) { + switch(event.name) { + case 'save': + this.save(event); + break; + case 'close': + this.returnToListPage(); + break; + case 'toggle-view': + this.formView = event.data; + break; + } + } + + override clear() { + this.formData.configTypeId = ''; + this.clearForm(); + } + + clearForm() { + this.items.forEach((item: any) => { + if (item?.component) item.component.destroy(); + }); + this.errors = {}; + this.items = []; + this.formData = new CertificateAuthority(); + if (this.subscription) this.subscription.unsubscribe(); + } + + override copyToClipboard(val) { + navigator.clipboard.writeText(val); + const growlerData = new GrowlerModel( + 'info', + 'Information', + `Token Copied`, + `Token copied to clipboard`, + ); + this.growlerService.show(growlerData); + } + + async save(event?: any) { + if(!this.validate()) { + return; + } + const tagVals = this.getTagValues(); + if (!isEmpty(tagVals)) { + forOwn(tagVals, (value, key) => { + this.formData.tags[key] = value; + }); + } + const apiData = this.apiData; + apiData.id = this.formData.id; + this.isLoading = true; + this.svc.save(apiData, this.certificate).then((result) => { + if (this.isModal) { + this.closeModal(true, true); + return; + } + this.initData = this.formData; + this._dataChange = false; + this.returnToListPage(); + }).catch((errorMessage) => { + this.errors.certPem = true; + this.certErrorMessage = errorMessage; + }).finally(() => { + this.isLoading = false; + }); + } + + validate() { + this.errors = {}; + const labels = []; + const growlers = []; + if (isEmpty(this.certificate)) { + this.errors.certPem = true; + this.certErrorMessage = 'Please enter or upload a valid certificate'; + growlers.push(new GrowlerModel( + 'error', + 'Invalid', + `Missing Certificate`, + this.certErrorMessage, + )); + } + return isEmpty(this.errors); + } + + get apiCallURL() { + return this.settings.selectedEdgeController + '/edge/management/v1/verify-certificate' + (this.formData.id ? `/${this.formData.id}` : ''); + } + + get apiData(): any { + const data: any = {}; + this._apiData = data; + return this._apiData; + } + + _apiData: any = {}; + set apiData(data) { + this._apiData = data; + } + + dataChanged(event) { + this._apiData = cloneDeep(this.apiData); + } + + + openFileSelect(event: any) { + this.filterInput.nativeElement.click(); + this.fileSelectOpening = true; + delay(() => { + this.fileSelectOpening = false; + }, 1000); + } + + selectPemFile(event: any) { + console.log(event); + const file: File = event?.target?.files[0]; + + if (file) { + const fileReader = new FileReader(); + fileReader.onload = (fileLoadedEvent) => { + const textFromSelectedFile: any = fileLoadedEvent.target?.result; + if (!this.validationService.isValidPEM(textFromSelectedFile?.trim())) { + this.errors.certPem = true; + const growlerData = new GrowlerModel( + 'error', + 'Invalid', + `Cert Invalid`, + `The file selected for the Certificate field is invalid. Please check your input and try again.`, + ); + this.growlerService.show(growlerData); + this.certificate = 'Invalid cert. Please select or enter a valid certificate.'; + } else { + unset(this.errors, 'certPem'); + this.certificate = textFromSelectedFile; + } + }; + fileReader.readAsText(file, "UTF-8"); + } + } + +} diff --git a/projects/ziti-console-lib/src/lib/features/projectable-forms/certificate-authority/verify-certificate/verify-certificate.service.ts b/projects/ziti-console-lib/src/lib/features/projectable-forms/certificate-authority/verify-certificate/verify-certificate.service.ts new file mode 100644 index 00000000..cde65bd7 --- /dev/null +++ b/projects/ziti-console-lib/src/lib/features/projectable-forms/certificate-authority/verify-certificate/verify-certificate.service.ts @@ -0,0 +1,57 @@ +import {Injectable, Inject} from '@angular/core'; +import {ZITI_DATA_SERVICE, ZitiDataService} from "../../../../services/ziti-data.service"; +import {GrowlerModel} from "../../../messaging/growler.model"; +import {GrowlerService} from "../../../messaging/growler.service"; +import {ExtensionService, SHAREDZ_EXTENSION} from "../../../extendable/extensions-noop.service"; +import {ValidationService} from "../../../../services/validation.service"; +import {CertificateAuthority} from "../../../../models/certificate-authority"; + +@Injectable({ + providedIn: 'root' +}) +export class VerifyCertificateService { + + items: any[] = []; + errors: any[] = []; + saveDisabled = false; + + paging = { + filter: "", + noSearch: true, + order: "asc", + page: 1, + searchOn: "name", + sort: "name", + total: 100 + } + + constructor( + @Inject(ZITI_DATA_SERVICE) private dataService: ZitiDataService, + @Inject(SHAREDZ_EXTENSION)private extService: ExtensionService, + private growlerService: GrowlerService, + private validationService: ValidationService + ) { + } + + save(formData, cert) { + return this.dataService.post(`cas/${formData.id}/verify`, cert, true, 'text/plain').then(async (result: any) => { + const growlerData = new GrowlerModel( + 'success', + 'Success', + `Certificate Verified`, + `Successfully verified certificate for this certificate authority`, + ); + this.growlerService.show(growlerData); + }).catch((resp) => { + const errorMessage = this.dataService.getErrorMessage(resp); + const growlerData = new GrowlerModel( + 'error', + 'Error', + `Error Verifying Certificate`, + errorMessage, + ); + this.growlerService.show(growlerData); + throw errorMessage; + }) + } +} diff --git a/projects/ziti-console-lib/src/lib/features/projectable-forms/form-field-container/form-field-container.component.html b/projects/ziti-console-lib/src/lib/features/projectable-forms/form-field-container/form-field-container.component.html index 2ecb9624..bfaea14c 100644 --- a/projects/ziti-console-lib/src/lib/features/projectable-forms/form-field-container/form-field-container.component.html +++ b/projects/ziti-console-lib/src/lib/features/projectable-forms/form-field-container/form-field-container.component.html @@ -21,6 +21,31 @@ matTooltipPosition="below" > +
    + + OFF + +
    +
    +
    +
    +
    +
    + + ON + +
    diff --git a/projects/ziti-console-lib/src/lib/features/projectable-forms/form-field-container/form-field-container.component.ts b/projects/ziti-console-lib/src/lib/features/projectable-forms/form-field-container/form-field-container.component.ts index 3678e0fb..18b9f56e 100644 --- a/projects/ziti-console-lib/src/lib/features/projectable-forms/form-field-container/form-field-container.component.ts +++ b/projects/ziti-console-lib/src/lib/features/projectable-forms/form-field-container/form-field-container.component.ts @@ -36,12 +36,26 @@ export class FormFieldContainerComponent { @Input() class = ''; @Input() contentStyle: any = ''; @Input() showHeader: any = true; + @Input() showToggle = false; @Input() headerActions: any[]; + @Input() headerToggle = false; @Output() actionRequested: EventEmitter = new EventEmitter(); + @Output() headerToggleChange: EventEmitter = new EventEmitter(); constructor() {} actionClicked(action) { this.actionRequested.emit(action); } + + toggleHeader(option?) { + if (option == 'left') { + this.headerToggle = false; + } else if (option === 'right') { + this.headerToggle = true; + } else { + this.headerToggle = !this.headerToggle; + } + this.headerToggleChange.emit(this.headerToggle); + } } diff --git a/projects/ziti-console-lib/src/lib/features/projectable-forms/form-header/form-header.component.html b/projects/ziti-console-lib/src/lib/features/projectable-forms/form-header/form-header.component.html index 59feedd4..57a29162 100644 --- a/projects/ziti-console-lib/src/lib/features/projectable-forms/form-header/form-header.component.html +++ b/projects/ziti-console-lib/src/lib/features/projectable-forms/form-header/form-header.component.html @@ -11,14 +11,14 @@
    -
    - - FORM - +
    + + FORM +
    = new EventEmitter(); @Output() actionRequested: EventEmitter = new EventEmitter(); diff --git a/projects/ziti-console-lib/src/lib/features/sidebars/side-banner/side-banner.component.scss b/projects/ziti-console-lib/src/lib/features/sidebars/side-banner/side-banner.component.scss index 7b680eb4..dc9439bc 100644 --- a/projects/ziti-console-lib/src/lib/features/sidebars/side-banner/side-banner.component.scss +++ b/projects/ziti-console-lib/src/lib/features/sidebars/side-banner/side-banner.component.scss @@ -2,7 +2,7 @@ max-width: 23.75rem; position: relative; display:inline-block; - height:100vh; + height:100%; background-image: url(../../../assets/images/Login.jpg); background-size: cover; background-position: center center; diff --git a/projects/ziti-console-lib/src/lib/features/sidebars/side-toolbar/side-toolbar.component.scss b/projects/ziti-console-lib/src/lib/features/sidebars/side-toolbar/side-toolbar.component.scss index 082d5bb0..b2e256fa 100644 --- a/projects/ziti-console-lib/src/lib/features/sidebars/side-toolbar/side-toolbar.component.scss +++ b/projects/ziti-console-lib/src/lib/features/sidebars/side-toolbar/side-toolbar.component.scss @@ -7,7 +7,7 @@ justify-content: space-between; width: 4rem; background: linear-gradient(to bottom, var(--primary) 0%, var(--secondary) 100%); - height: 100vh; + height: 100%; padding-top: 1rem; padding-bottom:1rem; diff --git a/projects/ziti-console-lib/src/lib/models/certificate-authority.ts b/projects/ziti-console-lib/src/lib/models/certificate-authority.ts new file mode 100644 index 00000000..85521f34 --- /dev/null +++ b/projects/ziti-console-lib/src/lib/models/certificate-authority.ts @@ -0,0 +1,13 @@ +export class CertificateAuthority { + name: string = ''; + id: string = ''; + isAutoCaEnrollmentEnabled: boolean = false; + isOttCaEnrollmentEnabled: boolean = false; + identityRoles: any[] = []; + identityNameFormat: string = ''; + isAuthEnabled: boolean = false; + certPem: string = ''; + externalIdClaim: any = undefined; + tags: any = {}; + verificationToke: string = ''; +} \ No newline at end of file diff --git a/projects/ziti-console-lib/src/lib/pages/certificate-authorities/certificate-authorities-page.component.ts b/projects/ziti-console-lib/src/lib/pages/certificate-authorities/certificate-authorities-page.component.ts index a6f3bc57..1be00de1 100644 --- a/projects/ziti-console-lib/src/lib/pages/certificate-authorities/certificate-authorities-page.component.ts +++ b/projects/ziti-console-lib/src/lib/pages/certificate-authorities/certificate-authorities-page.component.ts @@ -84,7 +84,10 @@ export class CertificateAuthoritiesPageComponent extends ListPageComponent imple this.svc.openEditForm(); break; case 'delete': - this.deleteItem(event.item) + this.deleteItem(event.item); + break; + case 'verify': + this.svc.verifyCert(event.item.id); break; case 'download-all': this.downloadAllItems(); diff --git a/projects/ziti-console-lib/src/lib/pages/certificate-authorities/certificate-authorities-page.service.ts b/projects/ziti-console-lib/src/lib/pages/certificate-authorities/certificate-authorities-page.service.ts index 7bbfae03..a67bcc8a 100644 --- a/projects/ziti-console-lib/src/lib/pages/certificate-authorities/certificate-authorities-page.service.ts +++ b/projects/ziti-console-lib/src/lib/pages/certificate-authorities/certificate-authorities-page.service.ts @@ -47,6 +47,7 @@ export class CertificateAuthoritiesPageService extends ListPageServiceClass { override menuItems = [ {name: 'Edit', action: 'update'}, + {name: 'Verify', action: 'verify'}, {name: 'Delete', action: 'delete'}, ] @@ -73,6 +74,15 @@ export class CertificateAuthoritiesPageService extends ListPageServiceClass { { label: 'Unverified', value: false }, ] }; + const enabledComponentParams = { + filterType: 'SELECT', + enableSorting: true, + filterOptions: [ + { label: 'All', value: '' }, + { label: 'Enabled', value: true }, + { label: 'Disabled', value: false }, + ] + }; const createdAtHeaderComponentParams = { filterType: 'DATETIME', }; @@ -114,6 +124,7 @@ export class CertificateAuthoritiesPageService extends ListPageServiceClass { field: 'isAutoCaEnrollmentEnabled', headerName: 'Auto Enrollment', headerComponent: TableColumnDefaultComponent, + headerComponentParams: enabledComponentParams, resizable: true, cellClass: 'nf-cell-vert-align tCol', sortable: true, @@ -125,6 +136,7 @@ export class CertificateAuthoritiesPageService extends ListPageServiceClass { field: 'isOttCaEnrollmentEnabled', headerName: 'OTT Auto', headerComponent: TableColumnDefaultComponent, + headerComponentParams: enabledComponentParams, resizable: true, cellClass: 'nf-cell-vert-align tCol', sortable: true, @@ -136,6 +148,7 @@ export class CertificateAuthoritiesPageService extends ListPageServiceClass { field: 'isAuthEnabled', headerName: 'Auth Enabled', headerComponent: TableColumnDefaultComponent, + headerComponentParams: enabledComponentParams, resizable: true, cellClass: 'nf-cell-vert-align tCol', sortable: true, @@ -177,7 +190,7 @@ export class CertificateAuthoritiesPageService extends ListPageServiceClass { private addActionsPerRow(results: any): any[] { return results.data.map((row) => { - row.actionList = ['update', 'delete']; + row.actionList = ['update', 'verify', 'delete',]; return row; }); } @@ -193,4 +206,9 @@ export class CertificateAuthoritiesPageService extends ListPageServiceClass { } this.sideModalOpen = true; } + + public verifyCert(itemId, basePath?) { + basePath = basePath ? basePath : this.basePath; + this.router?.navigateByUrl(`${basePath}/${itemId}/verify`); + } } diff --git a/projects/ziti-console-lib/src/lib/services/validation.service.ts b/projects/ziti-console-lib/src/lib/services/validation.service.ts index 5baaaf88..0e8e09df 100644 --- a/projects/ziti-console-lib/src/lib/services/validation.service.ts +++ b/projects/ziti-console-lib/src/lib/services/validation.service.ts @@ -93,21 +93,8 @@ export class ValidationService { } isValidPEM(cert) { - const header = '-----BEGIN CERTIFICATE-----'; - const footer = '-----END CERTIFICATE-----'; - - if (!cert.startsWith(header) || !cert.endsWith(footer)) { - return false; - } - - const base64Content = cert.slice(header.length, -footer.length).trim(); - - const isBase64 = (str) => { - const base64Pattern = /^(?:[A-Z0-9+/=]+\n)*[A-Z0-9+/=]+$/i; - return base64Pattern.test(str); - }; - - return isBase64(base64Content); + const pemRegex = /^-----BEGIN CERTIFICATE-----([A-Za-z0-9+/=\n\r]+)-----END CERTIFICATE-----$/; + return pemRegex.test(cert); } isValidURI(uri) { diff --git a/projects/ziti-console-lib/src/lib/services/ziti-controller-data.service.ts b/projects/ziti-console-lib/src/lib/services/ziti-controller-data.service.ts index 2cbdd8b6..f05e3c99 100644 --- a/projects/ziti-console-lib/src/lib/services/ziti-controller-data.service.ts +++ b/projects/ziti-console-lib/src/lib/services/ziti-controller-data.service.ts @@ -42,13 +42,19 @@ export class ZitiControllerDataService extends ZitiDataService { super(logger, growler, settingsService, httpClient, router); } - post(type, model, chained = false): Promise { + post(type, model, chained = false, contentType?): Promise { const apiVersions = this.settingsService.apiVersions || {}; const prefix = apiVersions["edge-management"]?.v1?.path; const url = this.settingsService.settings.selectedEdgeController; const serviceUrl = url + prefix + "/" + type; - - return firstValueFrom(this.httpClient.post(serviceUrl, model, {}).pipe( + let options = {}; + if (contentType) { + const headers = { + 'Content-Type': 'text/plain' + } + options = { headers }; + } + return firstValueFrom(this.httpClient.post(serviceUrl, model, options).pipe( catchError((err: any) => { const error = "Server Not Accessible"; if (err.code !== "ECONNREFUSED") throw(err); diff --git a/projects/ziti-console-lib/src/lib/services/ziti-data.service.ts b/projects/ziti-console-lib/src/lib/services/ziti-data.service.ts index e8060699..b5b9dcbb 100644 --- a/projects/ziti-console-lib/src/lib/services/ziti-data.service.ts +++ b/projects/ziti-console-lib/src/lib/services/ziti-data.service.ts @@ -52,7 +52,7 @@ export abstract class ZitiDataService { protected router: Router ) {} - abstract post(type, model, chained?): Promise; + abstract post(type, model, chained?, contentType?): Promise; abstract put(type, model, id, chained?): Promise; abstract patch(type, model, id, chained?): Promise; abstract get(type: string, paging: any, filters: FilterObj[], url?): Promise; @@ -86,4 +86,20 @@ export abstract class ZitiDataService { } return filters; } + + getErrorMessage(resp) { + let errorMessage; + if (resp?.error?.error?.message) { + errorMessage = resp?.error?.error?.message; + } else if (resp?.error?.error?.cause?.message) { + errorMessage = resp?.error?.error?.cause?.message; + } else if (resp?.error?.error?.cause?.reason) { + errorMessage = resp?.error?.error?.cause?.reason; + }else if (resp?.error?.message) { + errorMessage = resp?.error?.message; + } else { + errorMessage = 'An unknown error occurred'; + } + return errorMessage; + } } diff --git a/projects/ziti-console-lib/src/lib/shared-assets/styles/global.scss b/projects/ziti-console-lib/src/lib/shared-assets/styles/global.scss index 113cfc54..57c7433b 100644 --- a/projects/ziti-console-lib/src/lib/shared-assets/styles/global.scss +++ b/projects/ziti-console-lib/src/lib/shared-assets/styles/global.scss @@ -649,6 +649,15 @@ lib-form-field-container { background-color: var(--navigation); } } + +a { + &.download-button { + &:hover { + color: var(--white) + } + } +} + .download-button { display: flex; flex-direction: row; @@ -656,7 +665,7 @@ lib-form-field-container { justify-content: space-between; width: 100%; background-color: var(--primaryColor); - color: var(--background); + color: var(--white); text-transform: uppercase; font-size: 0.875rem; font-weight: 600; @@ -670,6 +679,7 @@ lib-form-field-container { outline: 0; filter: brightness(90%); box-shadow: 0 0.125rem 0.1875rem 0 var(--primaryColorOpaque); + color: var(--white); } &:active { @@ -693,8 +703,8 @@ lib-form-field-container { z-index: 10; } + .verify-certificate, .tap-to-download { - font-family: zac!important; speak: none; font-style: normal; font-weight: 400; @@ -707,10 +717,21 @@ lib-form-field-container { -moz-osx-font-smoothing: grayscale; position: relative; width: 2.8125rem; - margin-right: 0.625rem; background-size: contain; background-repeat: no-repeat; + } + .verify-certificate { + font-family: icomoon !important; + margin-left: var(--marginMedium); + &:before { + content: "\e958"; + } + } + + .tap-to-download { + font-family: zac !important; + margin-right: var(--marginMedium); &:before { content: "\e92d"; } @@ -1036,6 +1057,18 @@ lib-tag-selector { transition: 0.5s; left: 0; + &.form-toggle-switch-inverse { + .form-toggle-indicator { + border-color: var(--red); + } + + &.toggle-right { + .form-toggle-indicator { + border-color: var(--green); + } + } + } + &.toggle-right { left: 0.625rem; @@ -1097,6 +1130,11 @@ lib-tag-selector { .form-field-title { color: var(--offWhite); } + + &.disabled { + opacity: .8; + pointer-events: none; + } } .loginForm { @@ -1538,3 +1576,109 @@ p-dropdown { border: none; } } + +.radio-group-container { + display: flex; + gap: var(--marginLarge); + + &:focus { + .radio-button-container { + .radio-button-circle { + border-color: var(--primaryColor); + } + } + } + + .radio-button-container { + display: flex; + flex-direction: row; + align-items: center; + background-color: var(--formGroup); + border-radius: var(--inputBorderRadius); + width: 100%; + padding-left: var(--paddingMedium); + padding-right: var(--paddingMedium); + padding-top: var(--paddingLarge); + padding-bottom: var(--paddingLarge); + cursor: pointer; + gap: var(--marginMedium); + + .radio-button-circle { + display: flex; + width: 1.3125rem; + height: 1.3125rem; + border-radius: 1.3125rem; + border-width: 0.125rem; + border-style: solid; + border-color: var(--offWhite); + align-items: center; + justify-content: center; + background-color: var(--offWhite); + + .radio-button-inner-circle { + display: none; + width: 0.9375rem; + height: 0.9375rem; + border-radius: 0.9375rem; + align-items: center; + justify-content: center; + background-color: var(--primaryColor); + } + } + + &.selected { + .radio-button-circle { + .radio-button-inner-circle { + display: flex; + } + } + } + + &:active { + .radio-button-circle { + .radio-button-inner-circle { + display: flex; + background-color: var(--menu); + } + } + } + + .radio-button-label { + color: var(--offWhite); + font-size: 0.875rem; + font-weight: 600; + } + } +} + +.api-data-no-wrap{ + .jse-text-mode { + width: 100%; + .cm-editor { + width: 100%; + .cm-scroller { + width: 100%; + .cm-content { + width: 100%; + overflow: auto; + .ͼr { + white-space: nowrap; + } + } + } + } + } +} + +.copy-icon { + background-image: url(/assets/svgs/copy.svg); + background-size: 1.125rem; + background-repeat: no-repeat; + height: 1.25rem; + width: 1.25rem; + margin-left: var(--marginSmall);; +} + +.error-text { + color: var(--red); +} \ No newline at end of file diff --git a/projects/ziti-console-lib/src/lib/ziti-console-lib.module.ts b/projects/ziti-console-lib/src/lib/ziti-console-lib.module.ts index 2ef66694..16dfe32e 100644 --- a/projects/ziti-console-lib/src/lib/ziti-console-lib.module.ts +++ b/projects/ziti-console-lib/src/lib/ziti-console-lib.module.ts @@ -115,6 +115,10 @@ import {AuthPoliciesPageComponent} from "./pages/auth-policies/auth-policies-pag import {AuthPolicyFormComponent} from "./features/projectable-forms/auth-policy/auth-policy-form.component"; import {CertificateAuthoritiesPageComponent} from "./pages/certificate-authorities/certificate-authorities-page.component"; import {PreviewSelectionsComponent} from "./features/preview-selections/preview-selections.component"; +import {CertificateAuthorityFormComponent} from "./features/projectable-forms/certificate-authority/certificate-authority-form.component"; +import { + VerifyCertificateComponent +} from "./features/projectable-forms/certificate-authority/verify-certificate/verify-certificate.component"; export function playerFactory() { return import(/* webpackChunkName: 'lottie-web' */ 'lottie-web'); @@ -200,7 +204,9 @@ export function playerFactory() { AuthPoliciesPageComponent, AuthPolicyFormComponent, PreviewSelectionsComponent, - CertificateAuthoritiesPageComponent + CertificateAuthoritiesPageComponent, + CertificateAuthorityFormComponent, + VerifyCertificateComponent ], imports: [ CommonModule, diff --git a/projects/ziti-console-lib/src/public-api.ts b/projects/ziti-console-lib/src/public-api.ts index b1d8ee84..ee3409e5 100644 --- a/projects/ziti-console-lib/src/public-api.ts +++ b/projects/ziti-console-lib/src/public-api.ts @@ -83,6 +83,9 @@ export * from './lib/features/projectable-forms/jwt-signer/jwt-signer-form.servi export * from './lib/features/projectable-forms/jwt-signer/jwt-signer-form.component'; export * from './lib/features/projectable-forms/auth-policy/auth-policy-form.service'; export * from './lib/features/projectable-forms/auth-policy/auth-policy-form.component'; +export * from './lib/features/projectable-forms/certificate-authority/certificate-authority-form.service'; +export * from './lib/features/projectable-forms/certificate-authority/certificate-authority-form.component'; +export * from './lib/features/projectable-forms/certificate-authority/verify-certificate/verify-certificate.component'; export * from './lib/features/reset-enrollment/reset-enrollment.service'; export * from './lib/features/extendable/extensions-noop.service'; export * from './lib/features/projectable-forms/form-header/form-header.component'; diff --git a/release-notes.md b/release-notes.md index 60aba326..b09b9f44 100644 --- a/release-notes.md +++ b/release-notes.md @@ -1,6 +1,5 @@ # app-ziti-console-v3.7.1 # ziti-console-lib-v0.7.1 - ## Bug Fixes * [Issue #605](https://github.com/openziti/ziti-console/issues/605) - Remove delay in username & password change events during login * [Issue #607](https://github.com/openziti/ziti-console/issues/607) - Network Visualizer: Fix in node type name, color and subgroup size