Angular ServiceWorker fails with TrustedTypes

116 views Asked by At

For a single SPA Angular application, I want to use service workers ; but it conflicts with my CSP security rules...

main.ts:5 This document requires 'TrustedScriptURL' assignment.

Service worker registration failed with: TypeError: Failed to execute 'register' on 'ServiceWorkerContainer': This document requires 'TrustedScriptURL' assignment.

I tried to fix it with DOMPurify, then withcustom trusted-types policy, but without success...

Dependencies :

  • trusted-types 2.0.0
  • angular 16.2.6

app.config.ts

// [...]
import {trustedTypes} from 'trusted-types';

const myPolicy = trustedTypes.createPolicy('custom', {
  createScriptURL(dirty) {
    return dirty;
  },
})
export const appConfig: ApplicationConfig = {
  providers: [
    // [...]
    provideServiceWorker(myPolicy.createScriptURL(`/ngsw-worker.js`) as unknown as string, {
      enabled: !isDevMode(),
      registrationStrategy: 'registerWhenStable:30000',
    }),
  ],
};

CSP headers

require-trusted-types-for 'script'; trusted-types custom dompurify angular angular#bundler;

I don't know what I'm missing here :/

Thanks !

1

There are 1 answers

0
Joseph Simpson On

https://github.com/angular/angular/issues/45145 explains

Since navigator.serviceWorker.register() is considered an injection sink and you are using Trusted Types in your app, you must ensure that the string used to specify the SW script is trusted. How to do this depends on how you implement your policies.

and points to Angular.io as an example of a PWA that has solved this.

As advised, I installed the https://www.npmjs.com/package/safevalues package and made the relevant changes:

app.module.ts:

ServiceWorkerModule.register(
      unwrapResourceUrl(trustedResourceUrl`ngsw-worker.js`) as string,
      {
        enabled: environment.production,
        // Register the ServiceWorker as soon as the application is stable
        // or after 30 seconds (whichever comes first).
        registrationStrategy: "registerWhenStable:30000",
      }
    ),

After that, you just need to add "google#safe" to the trusted-types region of your CSP, e.g.

Content-Security-Policy: default-src 'self'; style-src 'self' 'unsafe-inline' fonts.googleapis.com; script-src 'self' 'unsafe-inline'; trusted-types angular angular#bundler google#safe; require-trusted-types-for 'script'; font-src fonts.gstatic.com; frame-ancestors 'none';