diff --git a/src/app/components/api/primengconfig.ts b/src/app/components/api/primengconfig.ts index f9f47913339..f5a806fcc7f 100644 --- a/src/app/components/api/primengconfig.ts +++ b/src/app/components/api/primengconfig.ts @@ -12,6 +12,8 @@ export class PrimeNGConfig { overlayOptions: OverlayOptions = {}; + csp = signal<{ nonce: string | undefined }>({ nonce: undefined }); + filterMatchModeOptions = { text: [FilterMatchMode.STARTS_WITH, FilterMatchMode.CONTAINS, FilterMatchMode.NOT_CONTAINS, FilterMatchMode.ENDS_WITH, FilterMatchMode.EQUALS, FilterMatchMode.NOT_EQUALS], numeric: [FilterMatchMode.EQUALS, FilterMatchMode.NOT_EQUALS, FilterMatchMode.LESS_THAN, FilterMatchMode.LESS_THAN_OR_EQUAL_TO, FilterMatchMode.GREATER_THAN, FilterMatchMode.GREATER_THAN_OR_EQUAL_TO], diff --git a/src/app/components/calendar/calendar.ts b/src/app/components/calendar/calendar.ts index 6d0f9d0387f..a874ea955dd 100644 --- a/src/app/components/calendar/calendar.ts +++ b/src/app/components/calendar/calendar.ts @@ -3558,6 +3558,7 @@ export class Calendar implements OnInit, OnDestroy, ControlValueAccessor { } (this.responsiveStyleElement).innerHTML = innerHTML; + DomHandler.setAttribute(this.responsiveStyleElement, 'nonce', this.config?.csp()?.nonce); } } diff --git a/src/app/components/carousel/carousel.ts b/src/app/components/carousel/carousel.ts index ed10709d1b7..1409301165e 100755 --- a/src/app/components/carousel/carousel.ts +++ b/src/app/components/carousel/carousel.ts @@ -520,6 +520,7 @@ export class Carousel implements AfterContentInit { if (!this.carouselStyle) { this.carouselStyle = this.renderer.createElement('style'); this.carouselStyle.type = 'text/css'; + DomHandler.setAttribute(this.carouselStyle, 'nonce', this.config?.csp()?.nonce); this.renderer.appendChild(this.document.head, this.carouselStyle); } diff --git a/src/app/components/confirmdialog/confirmdialog.ts b/src/app/components/confirmdialog/confirmdialog.ts index 6a803b12141..26d69b673f0 100755 --- a/src/app/components/confirmdialog/confirmdialog.ts +++ b/src/app/components/confirmdialog/confirmdialog.ts @@ -616,6 +616,7 @@ export class ConfirmDialog implements AfterContentInit, OnInit, OnDestroy { } this.styleElement.innerHTML = innerHTML; + DomHandler.setAttribute(this.styleElement, 'nonce', this.config?.csp()?.nonce); } } diff --git a/src/app/components/dialog/dialog.ts b/src/app/components/dialog/dialog.ts index 01bd042f87a..2d8fd9c1ec8 100755 --- a/src/app/components/dialog/dialog.ts +++ b/src/app/components/dialog/dialog.ts @@ -701,6 +701,7 @@ export class Dialog implements AfterContentInit, OnInit, OnDestroy { } this.renderer.setProperty(this.styleElement, 'innerHTML', innerHTML); + DomHandler.setAttribute(this.styleElement, 'nonce', this.config?.csp()?.nonce); } } } diff --git a/src/app/components/dynamicdialog/dynamicdialog.ts b/src/app/components/dynamicdialog/dynamicdialog.ts index 0e6f060f104..378ab0c535c 100755 --- a/src/app/components/dynamicdialog/dynamicdialog.ts +++ b/src/app/components/dynamicdialog/dynamicdialog.ts @@ -301,6 +301,7 @@ export class DynamicDialogComponent implements AfterViewInit, OnDestroy { } this.renderer.setProperty(this.styleElement, 'innerHTML', innerHTML); + DomHandler.setAttribute(this.styleElement, 'nonce', this.primeNGConfig?.csp()?.nonce); } } } diff --git a/src/app/components/galleria/galleria.ts b/src/app/components/galleria/galleria.ts index 09b7cffcb14..bf616dc89ee 100755 --- a/src/app/components/galleria/galleria.ts +++ b/src/app/components/galleria/galleria.ts @@ -1074,6 +1074,7 @@ export class GalleriaThumbnails implements OnInit, AfterContentChecked, AfterVie } this.thumbnailsStyle.innerHTML = innerHTML; + DomHandler.setAttribute(this.thumbnailsStyle, 'nonce', this.galleria.config?.csp()?.nonce); } calculatePosition() { diff --git a/src/app/components/orderlist/orderlist.ts b/src/app/components/orderlist/orderlist.ts index c2ce2a9ee7c..f7558fe7e8e 100755 --- a/src/app/components/orderlist/orderlist.ts +++ b/src/app/components/orderlist/orderlist.ts @@ -931,6 +931,7 @@ export class OrderList implements AfterViewChecked, AfterContentInit { } `; this.renderer.setProperty(this.styleElement, 'innerHTML', innerHTML); + DomHandler.setAttribute(this.styleElement, 'nonce', this.config?.csp()?.nonce); } } } diff --git a/src/app/components/picklist/picklist.ts b/src/app/components/picklist/picklist.ts index ea6b4ab3574..158aeecbd48 100755 --- a/src/app/components/picklist/picklist.ts +++ b/src/app/components/picklist/picklist.ts @@ -1651,6 +1651,7 @@ export class PickList implements AfterViewChecked, AfterContentInit { }`; this.renderer.setProperty(this.styleElement, 'innerHTML', innerHTML); + DomHandler.setAttribute(this.styleElement, 'nonce', this.config?.csp()?.nonce); } } } diff --git a/src/app/components/table/table.ts b/src/app/components/table/table.ts index 7db130cad16..89c318ba1e2 100644 --- a/src/app/components/table/table.ts +++ b/src/app/components/table/table.ts @@ -2975,6 +2975,7 @@ export class Table implements OnInit, AfterViewInit, AfterContentInit, Blockable this.styleElement = this.renderer.createElement('style'); this.styleElement.type = 'text/css'; this.renderer.appendChild(this.document.head, this.styleElement); + DomHandler.setAttribute(this.styleElement, 'nonce', this.config?.csp()?.nonce); } getGroupRowsMeta() { diff --git a/src/app/components/toast/toast.ts b/src/app/components/toast/toast.ts index 04071f81189..f05f2e86cb9 100755 --- a/src/app/components/toast/toast.ts +++ b/src/app/components/toast/toast.ts @@ -34,6 +34,7 @@ import { RippleModule } from 'primeng/ripple'; import { ObjectUtils, UniqueComponentId, ZIndexUtils } from 'primeng/utils'; import { Subscription } from 'rxjs'; import { ToastCloseEvent, ToastItemCloseEvent, ToastPositionType } from './toast.interface'; +import { DomHandler } from 'primeng/dom'; @Component({ selector: 'p-toastItem', @@ -480,6 +481,7 @@ export class Toast implements OnInit, AfterContentInit, OnDestroy { } this.renderer.setProperty(this.styleElement, 'innerHTML', innerHTML); + DomHandler.setAttribute(this.styleElement, 'nonce', this.config?.csp()?.nonce); } } diff --git a/src/app/showcase/doc/configuration/configurationdoc.module.ts b/src/app/showcase/doc/configuration/configurationdoc.module.ts index 9af5d0128a8..11e63dc9022 100644 --- a/src/app/showcase/doc/configuration/configurationdoc.module.ts +++ b/src/app/showcase/doc/configuration/configurationdoc.module.ts @@ -11,10 +11,11 @@ import { RepositoryDoc } from './locale/repositorydoc'; import { SetLocaleDoc } from './locale/setlocaledoc'; import { RippleDoc } from './rippledoc'; import { ZIndexDoc } from './zindexdoc'; +import { CspDoc } from './cspdoc'; @NgModule({ imports: [CommonModule, AppCodeModule, AppDocModule, RouterModule], exports: [AppDocModule], - declarations: [FilterModeDoc, ImportDoc, RippleDoc, ZIndexDoc, NgxTranslateDoc, ApiDoc, RepositoryDoc, SetLocaleDoc] + declarations: [FilterModeDoc, ImportDoc, CspDoc, RippleDoc, ZIndexDoc, NgxTranslateDoc, ApiDoc, RepositoryDoc, SetLocaleDoc] }) export class ConfigurationDocModule {} diff --git a/src/app/showcase/doc/configuration/cspdoc.ts b/src/app/showcase/doc/configuration/cspdoc.ts new file mode 100644 index 00000000000..17fad655c3f --- /dev/null +++ b/src/app/showcase/doc/configuration/cspdoc.ts @@ -0,0 +1,21 @@ +import { Component, inject } from '@angular/core'; +import { Code } from '@domain/code'; +import { PrimeNGConfig } from 'primeng/api'; + +@Component({ + selector: 'csp-doc', + template: ` + +

The nonce value to use on dynamically generated style elements in core.

+
+ + ` +}) +export class CspDoc { + code: Code = { + basic: `constructor(private primengConfig: PrimeNGConfig) { + this.config.csp.set({nonce: '...'}); +} + ` + }; +} diff --git a/src/app/showcase/pages/configuration/configurationdemo.component.ts b/src/app/showcase/pages/configuration/configurationdemo.component.ts index 57f4b109a92..6230bd077c8 100644 --- a/src/app/showcase/pages/configuration/configurationdemo.component.ts +++ b/src/app/showcase/pages/configuration/configurationdemo.component.ts @@ -1,4 +1,5 @@ import { Component } from '@angular/core'; +import { CspDoc } from '@doc/configuration/cspdoc'; import { FilterModeDoc } from '@doc/configuration/filtermodedoc'; import { ImportDoc } from '@doc/configuration/importdoc'; import { ApiDoc } from '@doc/configuration/locale/apidoc'; @@ -29,6 +30,17 @@ export class ConfigurationDemoComponent { label: 'ZIndex', component: ZIndexDoc }, + { + id: 'csp', + label: 'CSP', + children: [ + { + id: 'csp-nonce', + label: 'Nonce', + component: CspDoc + } + ] + }, { id: 'filter-mode', label: 'Filter Mode',