From 79aad28fbae90fd0fe84af65d9fa9341481f1813 Mon Sep 17 00:00:00 2001 From: Kristiyan Kostadinov Date: Tue, 28 Mar 2023 09:48:04 +0200 Subject: [PATCH] fix(@angular-devkit/build-angular): support CSP on critical CSS link tags. Based on https://github.com/angular/angular-cli/pull/24880#pullrequestreview-1347993316. Critters can generate `link` tags with inline `onload` handlers which breaks CSP. These changes update the style nonce processor to remove the `onload` handlers and replicate the behavior with an inline `script` tag that gets the proper nonce. Note that earlier we talked about doing this through Critters which while possible, would still require a custom HTML processor, because we need to both add and remove attributes from an element. --- .../src/builders/app-shell/app-shell_spec.ts | 26 ++++ .../utils/index-file/inline-critical-css.ts | 136 ++++++++++++++++++ .../index-file/inline-critical-css_spec.ts | 32 ++++- 3 files changed, 192 insertions(+), 2 deletions(-) diff --git a/packages/angular_devkit/build_angular/src/builders/app-shell/app-shell_spec.ts b/packages/angular_devkit/build_angular/src/builders/app-shell/app-shell_spec.ts index 809825cb8cc7..3a788a2adf9a 100644 --- a/packages/angular_devkit/build_angular/src/builders/app-shell/app-shell_spec.ts +++ b/packages/angular_devkit/build_angular/src/builders/app-shell/app-shell_spec.ts @@ -163,4 +163,30 @@ describe('AppShell Builder', () => { //, ); }); + + it('applies CSP nonce to critical CSS', async () => { + host.writeMultipleFiles(appShellRouteFiles); + host.replaceInFile('src/index.html', /p{color:#000}'); + expect(content).toContain(''); }); + + it('should process the inline `onload` handlers if a CSP nonce is specified', async () => { + const inlineCssProcessor = new InlineCriticalCssProcessor({ + readAsset, + }); + + const { content } = await inlineCssProcessor.process( + getContent('', ''), + { + outputPath: '/dist/', + }, + ); + + expect(content).toContain( + '', + ); + expect(content).toContain( + '', + ); + // Nonces shouldn't be added inside the `noscript` tags. + expect(content).toContain(''); + expect(content).toContain('