From 29fb463fc79cd3d8ee7d55120b547f42def7bd82 Mon Sep 17 00:00:00 2001 From: Rahul Zhade Date: Thu, 8 Dec 2022 13:49:58 -0800 Subject: [PATCH 1/7] Add concept of TrustedTypes policy Co-authored-by: Matt Langlois Co-authored-by: Kylie Stradley Co-authored-by: Jack McCracken --- src/index.ts | 1 + src/template-result.ts | 8 +++++++- src/trusted-types.ts | 15 +++++++++++++++ src/unsafe-html.ts | 6 +++++- 4 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 src/trusted-types.ts diff --git a/src/index.ts b/src/index.ts index 4eabd47..f9b313a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,3 +5,4 @@ export {html} from './html.js' export {isDirective, directive} from './directive.js' export {until} from './until.js' export {unsafeHTML} from './unsafe-html.js' +export {TrustedTypesPolicy} from './trusted-types.js' diff --git a/src/template-result.ts b/src/template-result.ts index bf8a666..5947e75 100644 --- a/src/template-result.ts +++ b/src/template-result.ts @@ -1,9 +1,11 @@ import {TemplateInstance, NodeTemplatePart} from '@github/template-parts' import type {TemplateTypeInit} from '@github/template-parts' +import {TrustedTypesPolicy} from './trusted-types.js' const templates = new WeakMap() const renderedTemplates = new WeakMap() const renderedTemplateInstances = new WeakMap() + export class TemplateResult { constructor( public readonly strings: TemplateStringsArray, @@ -17,7 +19,11 @@ export class TemplateResult { } else { const template = document.createElement('template') const end = this.strings.length - 1 - template.innerHTML = this.strings.reduce((str, cur, i) => str + cur + (i < end ? `{{ ${i} }}` : ''), '') + const html = this.strings.reduce((str, cur, i) => str + cur + (i < end ? `{{ ${i} }}` : ''), '') + const trustedHtml = TrustedTypesPolicy.cspTrustedTypesPolicy + ? (TrustedTypesPolicy.cspTrustedTypesPolicy.createHTML(html) as string) + : html + template.innerHTML = trustedHtml templates.set(this.strings, template) return template } diff --git a/src/trusted-types.ts b/src/trusted-types.ts new file mode 100644 index 0000000..0504958 --- /dev/null +++ b/src/trusted-types.ts @@ -0,0 +1,15 @@ +interface CSPTrustedHTMLToStringable { + toString: () => string +} + +interface CSPTrustedTypesPolicy { + createHTML: (s: string) => CSPTrustedHTMLToStringable +} + +export class TrustedTypesPolicy { + static cspTrustedTypesPolicy: CSPTrustedTypesPolicy | null = null + + static setTrustedTypesPolicy(policy: CSPTrustedTypesPolicy | null): void { + TrustedTypesPolicy.cspTrustedTypesPolicy = policy + } +} diff --git a/src/unsafe-html.ts b/src/unsafe-html.ts index f35f714..f9b5c14 100644 --- a/src/unsafe-html.ts +++ b/src/unsafe-html.ts @@ -1,11 +1,15 @@ import {directive} from './directive.js' import {NodeTemplatePart} from '@github/template-parts' import type {TemplatePart} from '@github/template-parts' +import {TrustedTypesPolicy} from './trusted-types.js' export const unsafeHTML = directive((value: string) => (part: TemplatePart) => { if (!(part instanceof NodeTemplatePart)) return const template = document.createElement('template') - template.innerHTML = value + const trustedValue = TrustedTypesPolicy.cspTrustedTypesPolicy + ? (TrustedTypesPolicy.cspTrustedTypesPolicy.createHTML(value) as string) + : value + template.innerHTML = trustedValue const fragment = document.importNode(template.content, true) part.replace(...fragment.childNodes) }) From 5269718227e7a4e33441fdce1fdd2ce34e6d7e8d Mon Sep 17 00:00:00 2001 From: Rahul Zhade Date: Thu, 8 Dec 2022 14:27:10 -0800 Subject: [PATCH 2/7] Testing that one can set a global TT policy Co-authored-by: Matt Langlois Co-authored-by: Kylie Stradley Co-authored-by: Jack McCracken --- test/trusted-types.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 test/trusted-types.ts diff --git a/test/trusted-types.ts b/test/trusted-types.ts new file mode 100644 index 0000000..4042ce8 --- /dev/null +++ b/test/trusted-types.ts @@ -0,0 +1,14 @@ +import {expect} from 'chai' +import {TrustedTypesPolicy} from '../lib/index.js' + +describe('trusted types', () => { + it('can set a CSP Trusted Types policy', () => { + const dummyPolicy = { + createHTML: (htmlText: string) => { + return htmlText + } + } + TrustedTypesPolicy.setTrustedTypesPolicy(dummyPolicy) + expect(TrustedTypesPolicy.cspTrustedTypesPolicy).to.equal(dummyPolicy) + }) +}) From c88a7a6f45425e01065f088ed01a08b1d192d559 Mon Sep 17 00:00:00 2001 From: Rahul Zhade Date: Thu, 8 Dec 2022 16:01:51 -0800 Subject: [PATCH 3/7] Update to use variable instead of class Co-authored-by: Lucas Garron --- src/index.ts | 2 +- src/template-result.ts | 6 ++---- src/trusted-types.ts | 12 +++++++----- src/unsafe-html.ts | 6 ++---- 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/index.ts b/src/index.ts index f9b313a..3fff533 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,4 +5,4 @@ export {html} from './html.js' export {isDirective, directive} from './directive.js' export {until} from './until.js' export {unsafeHTML} from './unsafe-html.js' -export {TrustedTypesPolicy} from './trusted-types.js' +export {setCSPTrustedTypesPolicy} from './trusted-types.js' diff --git a/src/template-result.ts b/src/template-result.ts index 5947e75..584f1de 100644 --- a/src/template-result.ts +++ b/src/template-result.ts @@ -1,6 +1,6 @@ import {TemplateInstance, NodeTemplatePart} from '@github/template-parts' import type {TemplateTypeInit} from '@github/template-parts' -import {TrustedTypesPolicy} from './trusted-types.js' +import {getCSPTrustedTypesPolicy} from './trusted-types.js' const templates = new WeakMap() const renderedTemplates = new WeakMap() @@ -20,9 +20,7 @@ export class TemplateResult { const template = document.createElement('template') const end = this.strings.length - 1 const html = this.strings.reduce((str, cur, i) => str + cur + (i < end ? `{{ ${i} }}` : ''), '') - const trustedHtml = TrustedTypesPolicy.cspTrustedTypesPolicy - ? (TrustedTypesPolicy.cspTrustedTypesPolicy.createHTML(html) as string) - : html + const trustedHtml = getCSPTrustedTypesPolicy() ? (getCSPTrustedTypesPolicy()?.createHTML(html) as string) : html template.innerHTML = trustedHtml templates.set(this.strings, template) return template diff --git a/src/trusted-types.ts b/src/trusted-types.ts index 0504958..d9855b9 100644 --- a/src/trusted-types.ts +++ b/src/trusted-types.ts @@ -6,10 +6,12 @@ interface CSPTrustedTypesPolicy { createHTML: (s: string) => CSPTrustedHTMLToStringable } -export class TrustedTypesPolicy { - static cspTrustedTypesPolicy: CSPTrustedTypesPolicy | null = null +let cspTrustedTypesPolicy: CSPTrustedTypesPolicy | null = null - static setTrustedTypesPolicy(policy: CSPTrustedTypesPolicy | null): void { - TrustedTypesPolicy.cspTrustedTypesPolicy = policy - } +export function getCSPTrustedTypesPolicy() { + return cspTrustedTypesPolicy +} + +export function setCSPTrustedTypesPolicy(policy: CSPTrustedTypesPolicy | null) { + cspTrustedTypesPolicy = policy } diff --git a/src/unsafe-html.ts b/src/unsafe-html.ts index f9b5c14..2143ce2 100644 --- a/src/unsafe-html.ts +++ b/src/unsafe-html.ts @@ -1,14 +1,12 @@ import {directive} from './directive.js' import {NodeTemplatePart} from '@github/template-parts' import type {TemplatePart} from '@github/template-parts' -import {TrustedTypesPolicy} from './trusted-types.js' +import {getCSPTrustedTypesPolicy} from './trusted-types.js' export const unsafeHTML = directive((value: string) => (part: TemplatePart) => { if (!(part instanceof NodeTemplatePart)) return const template = document.createElement('template') - const trustedValue = TrustedTypesPolicy.cspTrustedTypesPolicy - ? (TrustedTypesPolicy.cspTrustedTypesPolicy.createHTML(value) as string) - : value + const trustedValue = getCSPTrustedTypesPolicy() ? (getCSPTrustedTypesPolicy()?.createHTML(value) as string) : value template.innerHTML = trustedValue const fragment = document.importNode(template.content, true) part.replace(...fragment.childNodes) From e47453ee4d31441e8c35c628b4c2c15c99ff6a56 Mon Sep 17 00:00:00 2001 From: Rahul Zhade Date: Thu, 8 Dec 2022 16:02:43 -0800 Subject: [PATCH 4/7] Add tests --- .eslintrc.json | 3 ++- test/render.ts | 23 ++++++++++++++++++++++- test/trusted-types.ts | 12 +++++++++--- test/unsafe-html.ts | 22 +++++++++++++++++++++- 4 files changed, 54 insertions(+), 6 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index f726865..c046913 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -7,7 +7,8 @@ "no-invalid-this": "off", "@typescript-eslint/no-invalid-this": ["error"], "import/extensions": ["error", "always"], - "github/no-inner-html": "off" + "github/no-inner-html": "off", + "@typescript-eslint/no-unused-vars": ["error", { "vars": "all", "argsIgnorePattern": "^_" }] }, "overrides": [ { diff --git a/test/render.ts b/test/render.ts index 1263a93..8a2765c 100644 --- a/test/render.ts +++ b/test/render.ts @@ -1,5 +1,5 @@ import {expect} from 'chai' -import {html, render} from '../lib/index.js' +import {html, render, setCSPTrustedTypesPolicy} from '../lib/index.js' import type {TemplateResult} from '../lib/index.js' describe('render', () => { @@ -8,6 +8,10 @@ describe('render', () => { surface = document.createElement('section') }) + afterEach(() => { + setCSPTrustedTypesPolicy(null) + }) + it('memoizes by TemplateResult#template, updating old templates with new values', () => { const main = (x: string | null = null) => html`
` render(main('foo'), surface) @@ -55,4 +59,21 @@ describe('render', () => { expect(surface.innerHTML).to.contain('
') }) }) + + describe('trusted types', () => { + it('respects a Trusted Types Policy if it is set', () => { + let policyCalled = false + const rewrittenFragment = '
' + setCSPTrustedTypesPolicy({ + createHTML: (_html: string) => { + policyCalled = true + return rewrittenFragment + } + }) + const main = (x: string | null = null) => html`
` + render(main('foo'), surface) + expect(surface.innerHTML).to.equal(rewrittenFragment) + expect(policyCalled).to.be.true + }) + }) }) diff --git a/test/trusted-types.ts b/test/trusted-types.ts index 4042ce8..1008867 100644 --- a/test/trusted-types.ts +++ b/test/trusted-types.ts @@ -1,14 +1,20 @@ import {expect} from 'chai' -import {TrustedTypesPolicy} from '../lib/index.js' +import {setCSPTrustedTypesPolicy} from '../lib/index.js' +import {getCSPTrustedTypesPolicy} from '../lib/trusted-types.js' describe('trusted types', () => { + after(() => { + setCSPTrustedTypesPolicy(null) + }) + it('can set a CSP Trusted Types policy', () => { const dummyPolicy = { createHTML: (htmlText: string) => { return htmlText } } - TrustedTypesPolicy.setTrustedTypesPolicy(dummyPolicy) - expect(TrustedTypesPolicy.cspTrustedTypesPolicy).to.equal(dummyPolicy) + expect(getCSPTrustedTypesPolicy()).to.equal(null) + setCSPTrustedTypesPolicy(dummyPolicy) + expect(getCSPTrustedTypesPolicy()).to.equal(dummyPolicy) }) }) diff --git a/test/unsafe-html.ts b/test/unsafe-html.ts index b17db05..aac0cb5 100644 --- a/test/unsafe-html.ts +++ b/test/unsafe-html.ts @@ -1,7 +1,13 @@ import {expect} from 'chai' -import {html, render, unsafeHTML} from '../lib/index.js' +import {html, render, setCSPTrustedTypesPolicy, unsafeHTML} from '../lib/index.js' describe('unsafeHTML', () => { + beforeEach(() => { + setCSPTrustedTypesPolicy(null) + }) + afterEach(() => { + setCSPTrustedTypesPolicy(null) + }) it('renders basic text', async () => { const surface = document.createElement('section') render(html`
${unsafeHTML('Hello World')}
`, surface) @@ -31,4 +37,18 @@ describe('unsafeHTML', () => { render(fn('Universe'), surface) expect(surface.innerHTML).to.equal('') }) + it('respects trusted types', async () => { + let policyCalled = false + const rewrittenFragment = '
This has been rewritten by Trusted Types.
' + setCSPTrustedTypesPolicy({ + createHTML: (_html: string) => { + policyCalled = true + return rewrittenFragment + } + }) + const surface = document.createElement('section') + render(html`
${unsafeHTML('HelloWorld')}
`, surface) + expect(surface.innerHTML).to.equal(rewrittenFragment) + expect(policyCalled).to.be.true + }) }) From 0e400219696837ba9845844842f260bc07c182da Mon Sep 17 00:00:00 2001 From: Rahul Zhade Date: Thu, 8 Dec 2022 16:17:30 -0800 Subject: [PATCH 5/7] Update docs --- README.md | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/README.md b/README.md index 4bb8ec2..85585b4 100644 --- a/README.md +++ b/README.md @@ -245,3 +245,30 @@ render(html`
${until(request, timeout, loading)}
`) // ^ renders
Loading...
// After 2000ms will render
Failed to load
``` + +### CSP Trusted Types + +You can call `setCSPTrustedTypesPolicy(policy: TrustedTypePolicy | Promise | null)` from JavaScript to set a [CSP trusted types policy](https://web.dev/trusted-types/), which can perform (synchronous) filtering or rejection of the rendered template: + +```ts +import {setCspTrustedTypePolicy} from "@github/jtml"; +import DOMPurify from "dompurify"; // Using https://github.com/cure53/DOMPurify + +// This policy removes all HTML markup except links. +const policy = trustedTypes.createPolicy("links-only", { + createHTML: (htmlText: string) => { + return DOMPurify.sanitize(htmlText, { + ALLOWED_TAGS: ["a"], + ALLOWED_ATTR: ["href"], + RETURN_TRUSTED_TYPE: true, + }); + }, +}); +setCSPTrustedTypesPolicy(policy); +``` + +Note that: + +- Only a single policy can be set, shared by all `render` and `unsafeHTML` calls. +- You should call `setCSPTrustedTypesPolicy()` ahead of any other call of `@github/jtml` in your code. +- Not all browsers [support the trusted types API in JavaScript](https://caniuse.com/mdn-api_trustedtypes). You may want to use the [recommended tinyfill](https://github.com/w3c/trusted-types#tinyfill) to construct a policy without causing issues in other browsers. From 1e02b01acdb3b11bc873433d0049fc56ded70068 Mon Sep 17 00:00:00 2001 From: Rahul Zhade Date: Fri, 9 Dec 2022 11:13:25 -0800 Subject: [PATCH 6/7] Move setCspTrustedPolicy into TemplateResult class --- README.md | 8 ++++---- src/index.ts | 1 - src/template-result.ts | 19 +++++++++++++++++-- src/trusted-types.ts | 17 ----------------- src/unsafe-html.ts | 6 ++++-- test/render.ts | 6 +++--- test/trusted-types.ts | 11 +++++------ test/unsafe-html.ts | 8 ++++---- 8 files changed, 37 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 85585b4..6a89066 100644 --- a/README.md +++ b/README.md @@ -248,10 +248,10 @@ render(html`
${until(request, timeout, loading)}
`) ### CSP Trusted Types -You can call `setCSPTrustedTypesPolicy(policy: TrustedTypePolicy | Promise | null)` from JavaScript to set a [CSP trusted types policy](https://web.dev/trusted-types/), which can perform (synchronous) filtering or rejection of the rendered template: +You can call `TemplateResult.setCSPTrustedTypesPolicy(policy: TrustedTypePolicy | Promise | null)` from JavaScript to set a [CSP trusted types policy](https://web.dev/trusted-types/), which can perform (synchronous) filtering or rejection of the rendered template: ```ts -import {setCspTrustedTypePolicy} from "@github/jtml"; +import {TemplateResult} from "@github/jtml"; import DOMPurify from "dompurify"; // Using https://github.com/cure53/DOMPurify // This policy removes all HTML markup except links. @@ -264,11 +264,11 @@ const policy = trustedTypes.createPolicy("links-only", { }); }, }); -setCSPTrustedTypesPolicy(policy); +TemplateResult.setCSPTrustedTypesPolicy(policy); ``` Note that: - Only a single policy can be set, shared by all `render` and `unsafeHTML` calls. -- You should call `setCSPTrustedTypesPolicy()` ahead of any other call of `@github/jtml` in your code. +- You should call `TemplateResult.setCSPTrustedTypesPolicy()` ahead of any other call of `@github/jtml` in your code. - Not all browsers [support the trusted types API in JavaScript](https://caniuse.com/mdn-api_trustedtypes). You may want to use the [recommended tinyfill](https://github.com/w3c/trusted-types#tinyfill) to construct a policy without causing issues in other browsers. diff --git a/src/index.ts b/src/index.ts index 3fff533..4eabd47 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,4 +5,3 @@ export {html} from './html.js' export {isDirective, directive} from './directive.js' export {until} from './until.js' export {unsafeHTML} from './unsafe-html.js' -export {setCSPTrustedTypesPolicy} from './trusted-types.js' diff --git a/src/template-result.ts b/src/template-result.ts index 584f1de..7208345 100644 --- a/src/template-result.ts +++ b/src/template-result.ts @@ -1,11 +1,18 @@ import {TemplateInstance, NodeTemplatePart} from '@github/template-parts' import type {TemplateTypeInit} from '@github/template-parts' -import {getCSPTrustedTypesPolicy} from './trusted-types.js' const templates = new WeakMap() const renderedTemplates = new WeakMap() const renderedTemplateInstances = new WeakMap() +interface CSPTrustedHTMLToStringable { + toString: () => string +} + +interface CSPTrustedTypesPolicy { + createHTML: (s: string) => CSPTrustedHTMLToStringable +} + export class TemplateResult { constructor( public readonly strings: TemplateStringsArray, @@ -13,6 +20,12 @@ export class TemplateResult { public processor: TemplateTypeInit ) {} + static cspTrustedTypesPolicy: CSPTrustedTypesPolicy | null = null + + static setCSPTrustedTypesPolicy(policy: CSPTrustedTypesPolicy | null) { + TemplateResult.cspTrustedTypesPolicy = policy + } + get template(): HTMLTemplateElement { if (templates.has(this.strings)) { return templates.get(this.strings)! @@ -20,7 +33,9 @@ export class TemplateResult { const template = document.createElement('template') const end = this.strings.length - 1 const html = this.strings.reduce((str, cur, i) => str + cur + (i < end ? `{{ ${i} }}` : ''), '') - const trustedHtml = getCSPTrustedTypesPolicy() ? (getCSPTrustedTypesPolicy()?.createHTML(html) as string) : html + const trustedHtml = TemplateResult.cspTrustedTypesPolicy + ? (TemplateResult.cspTrustedTypesPolicy.createHTML(html) as string) + : html template.innerHTML = trustedHtml templates.set(this.strings, template) return template diff --git a/src/trusted-types.ts b/src/trusted-types.ts index d9855b9..e69de29 100644 --- a/src/trusted-types.ts +++ b/src/trusted-types.ts @@ -1,17 +0,0 @@ -interface CSPTrustedHTMLToStringable { - toString: () => string -} - -interface CSPTrustedTypesPolicy { - createHTML: (s: string) => CSPTrustedHTMLToStringable -} - -let cspTrustedTypesPolicy: CSPTrustedTypesPolicy | null = null - -export function getCSPTrustedTypesPolicy() { - return cspTrustedTypesPolicy -} - -export function setCSPTrustedTypesPolicy(policy: CSPTrustedTypesPolicy | null) { - cspTrustedTypesPolicy = policy -} diff --git a/src/unsafe-html.ts b/src/unsafe-html.ts index 2143ce2..070f26f 100644 --- a/src/unsafe-html.ts +++ b/src/unsafe-html.ts @@ -1,12 +1,14 @@ import {directive} from './directive.js' import {NodeTemplatePart} from '@github/template-parts' import type {TemplatePart} from '@github/template-parts' -import {getCSPTrustedTypesPolicy} from './trusted-types.js' +import {TemplateResult} from './template-result.js' export const unsafeHTML = directive((value: string) => (part: TemplatePart) => { if (!(part instanceof NodeTemplatePart)) return const template = document.createElement('template') - const trustedValue = getCSPTrustedTypesPolicy() ? (getCSPTrustedTypesPolicy()?.createHTML(value) as string) : value + const trustedValue = TemplateResult.cspTrustedTypesPolicy + ? (TemplateResult.cspTrustedTypesPolicy.createHTML(value) as string) + : value template.innerHTML = trustedValue const fragment = document.importNode(template.content, true) part.replace(...fragment.childNodes) diff --git a/test/render.ts b/test/render.ts index 8a2765c..519e1e1 100644 --- a/test/render.ts +++ b/test/render.ts @@ -1,5 +1,5 @@ import {expect} from 'chai' -import {html, render, setCSPTrustedTypesPolicy} from '../lib/index.js' +import {html, render, TemplateResult} from '../lib/index.js' import type {TemplateResult} from '../lib/index.js' describe('render', () => { @@ -9,7 +9,7 @@ describe('render', () => { }) afterEach(() => { - setCSPTrustedTypesPolicy(null) + TemplateResult.setCSPTrustedTypesPolicy(null) }) it('memoizes by TemplateResult#template, updating old templates with new values', () => { @@ -64,7 +64,7 @@ describe('render', () => { it('respects a Trusted Types Policy if it is set', () => { let policyCalled = false const rewrittenFragment = '
' - setCSPTrustedTypesPolicy({ + TemplateResult.setCSPTrustedTypesPolicy({ createHTML: (_html: string) => { policyCalled = true return rewrittenFragment diff --git a/test/trusted-types.ts b/test/trusted-types.ts index 1008867..3045d1f 100644 --- a/test/trusted-types.ts +++ b/test/trusted-types.ts @@ -1,10 +1,9 @@ import {expect} from 'chai' -import {setCSPTrustedTypesPolicy} from '../lib/index.js' -import {getCSPTrustedTypesPolicy} from '../lib/trusted-types.js' +import {TemplateResult} from '../lib/index.js' describe('trusted types', () => { after(() => { - setCSPTrustedTypesPolicy(null) + TemplateResult.setCSPTrustedTypesPolicy(null) }) it('can set a CSP Trusted Types policy', () => { @@ -13,8 +12,8 @@ describe('trusted types', () => { return htmlText } } - expect(getCSPTrustedTypesPolicy()).to.equal(null) - setCSPTrustedTypesPolicy(dummyPolicy) - expect(getCSPTrustedTypesPolicy()).to.equal(dummyPolicy) + expect(TemplateResult.cspTrustedTypesPolicy).to.equal(null) + TemplateResult.setCSPTrustedTypesPolicy(dummyPolicy) + expect(TemplateResult.cspTrustedTypesPolicy).to.equal(dummyPolicy) }) }) diff --git a/test/unsafe-html.ts b/test/unsafe-html.ts index aac0cb5..997ff8a 100644 --- a/test/unsafe-html.ts +++ b/test/unsafe-html.ts @@ -1,12 +1,12 @@ import {expect} from 'chai' -import {html, render, setCSPTrustedTypesPolicy, unsafeHTML} from '../lib/index.js' +import {html, render, TemplateResult, unsafeHTML} from '../lib/index.js' describe('unsafeHTML', () => { beforeEach(() => { - setCSPTrustedTypesPolicy(null) + TemplateResult.setCSPTrustedTypesPolicy(null) }) afterEach(() => { - setCSPTrustedTypesPolicy(null) + TemplateResult.setCSPTrustedTypesPolicy(null) }) it('renders basic text', async () => { const surface = document.createElement('section') @@ -40,7 +40,7 @@ describe('unsafeHTML', () => { it('respects trusted types', async () => { let policyCalled = false const rewrittenFragment = '
This has been rewritten by Trusted Types.
' - setCSPTrustedTypesPolicy({ + TemplateResult.setCSPTrustedTypesPolicy({ createHTML: (_html: string) => { policyCalled = true return rewrittenFragment From 186f0945a4082b0dfc42700c67b66dbd554e4b7e Mon Sep 17 00:00:00 2001 From: Rahul Zhade Date: Fri, 9 Dec 2022 11:36:19 -0800 Subject: [PATCH 7/7] More concise JS syntax Co-authored-by: Lucas Garron --- src/template-result.ts | 4 +--- src/unsafe-html.ts | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/template-result.ts b/src/template-result.ts index 7208345..6b17fc7 100644 --- a/src/template-result.ts +++ b/src/template-result.ts @@ -33,9 +33,7 @@ export class TemplateResult { const template = document.createElement('template') const end = this.strings.length - 1 const html = this.strings.reduce((str, cur, i) => str + cur + (i < end ? `{{ ${i} }}` : ''), '') - const trustedHtml = TemplateResult.cspTrustedTypesPolicy - ? (TemplateResult.cspTrustedTypesPolicy.createHTML(html) as string) - : html + const trustedHtml = (TemplateResult.cspTrustedTypesPolicy?.createHTML(html) as string | undefined) ?? html template.innerHTML = trustedHtml templates.set(this.strings, template) return template diff --git a/src/unsafe-html.ts b/src/unsafe-html.ts index 070f26f..ff757b5 100644 --- a/src/unsafe-html.ts +++ b/src/unsafe-html.ts @@ -6,9 +6,7 @@ import {TemplateResult} from './template-result.js' export const unsafeHTML = directive((value: string) => (part: TemplatePart) => { if (!(part instanceof NodeTemplatePart)) return const template = document.createElement('template') - const trustedValue = TemplateResult.cspTrustedTypesPolicy - ? (TemplateResult.cspTrustedTypesPolicy.createHTML(value) as string) - : value + const trustedValue = (TemplateResult.cspTrustedTypesPolicy?.createHTML(value) as string | undefined) ?? value template.innerHTML = trustedValue const fragment = document.importNode(template.content, true) part.replace(...fragment.childNodes)