From c73196eb5921d30667d53b37e3ec052f39be71e1 Mon Sep 17 00:00:00 2001 From: Vikram Subramanian Date: Thu, 24 May 2018 16:04:04 -0700 Subject: [PATCH] fix(platform-server): provide Domino DOM types globally (#24116) Fixes #23280, #23133. This fix lets code access DOM types like Node, HTMLElement in the code. These are invariant across requests and the corresponding classes from Domino can be safely provided during platform initialization. This is needed for the current sanitizer to work properly on platform-server. Also allows HTML types in injection - Ex. `@inject(DOCUMENT) doc: Document`. PR Close #24116 --- .../platform-server/src/domino_adapter.ts | 11 ++++++- .../platform-server/test/integration_spec.ts | 29 ++++++++++++++++++- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/packages/platform-server/src/domino_adapter.ts b/packages/platform-server/src/domino_adapter.ts index 8ea4035c80..17bf3c4fc9 100644 --- a/packages/platform-server/src/domino_adapter.ts +++ b/packages/platform-server/src/domino_adapter.ts @@ -13,6 +13,12 @@ function _notImplemented(methodName: string) { return new Error('This method is not implemented in DominoAdapter: ' + methodName); } +function setDomTypes() { + // Make all Domino types available as types in the global env. + Object.assign(global, domino.impl); + (global as any)['KeyboardEvent'] = domino.impl.Event; +} + /** * Parses a document string to a Document object. */ @@ -33,7 +39,10 @@ export function serializeDocument(doc: Document): string { * DOM Adapter for the server platform based on https://github.com/fgnass/domino. */ export class DominoAdapter extends BrowserDomAdapter { - static makeCurrent() { setRootDomAdapter(new DominoAdapter()); } + static makeCurrent() { + setDomTypes(); + setRootDomAdapter(new DominoAdapter()); + } private static defaultDoc: Document; diff --git a/packages/platform-server/test/integration_spec.ts b/packages/platform-server/test/integration_spec.ts index 092e135153..bc27c9d856 100644 --- a/packages/platform-server/test/integration_spec.ts +++ b/packages/platform-server/test/integration_spec.ts @@ -10,7 +10,7 @@ import {AnimationBuilder, animate, style, transition, trigger} from '@angular/an import {APP_BASE_HREF, PlatformLocation, isPlatformServer} from '@angular/common'; import {HttpClient, HttpClientModule} from '@angular/common/http'; import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing'; -import {ApplicationRef, CompilerFactory, Component, HostListener, Input, NgModule, NgModuleRef, NgZone, PLATFORM_ID, PlatformRef, ViewEncapsulation, destroyPlatform, getPlatform} from '@angular/core'; +import {ApplicationRef, CompilerFactory, Component, HostListener, Inject, Input, NgModule, NgModuleRef, NgZone, PLATFORM_ID, PlatformRef, ViewEncapsulation, destroyPlatform, getPlatform} from '@angular/core'; import {TestBed, async, inject} from '@angular/core/testing'; import {Http, HttpModule, Response, ResponseOptions, XHRBackend} from '@angular/http'; import {MockBackend, MockConnection} from '@angular/http/testing'; @@ -254,6 +254,20 @@ class MyInputComponent { class NameModule { } +@Component({selector: 'app', template: '
'}) +class HTMLTypesApp { + html = 'foo bar'; + constructor(@Inject(DOCUMENT) doc: Document) {} +} + +@NgModule({ + declarations: [HTMLTypesApp], + imports: [BrowserModule.withServerTransition({appId: 'inner-html'}), ServerModule], + bootstrap: [HTMLTypesApp] +}) +class HTMLTypesModule { +} + const TEST_KEY = makeStateKey('test'); const STRING_KEY = makeStateKey('testString'); @@ -552,6 +566,19 @@ class EscapedTransferStoreModule { }); })); + it('should work with sanitizer to handle "innerHTML"', async(() => { + // Clear out any global states. These should be set when platform-server + // is initialized. + (global as any).Node = undefined; + (global as any).Document = undefined; + renderModule(HTMLTypesModule, {document: doc}).then(output => { + expect(output).toBe( + '' + + '
foo bar
'); + called = true; + }); + })); + it('should call render hook', async(() => { renderModule(RenderHookModule, {document: doc}).then(output => { // title should be added by the render hook.