mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
This commit removes unnecessary transfer state escaping and updates this process to be done by the means of a `replacer` and `reviver` method as this removes the need to export the escaping and unescaping methods. The only thing that we need to escape is `<script` and `</script` which are done by the browsers, but not Node.js. PR Close #50201
86 lines
3 KiB
TypeScript
86 lines
3 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright Google LLC All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by an MIT-style license that can be
|
|
* found in the LICENSE file at https://angular.io/license
|
|
*/
|
|
|
|
import {Component, makeStateKey, NgModule, TransferState} from '@angular/core';
|
|
import {BrowserModule} from '@angular/platform-browser';
|
|
import {renderModule, ServerModule} from '@angular/platform-server';
|
|
|
|
describe('transfer_state', () => {
|
|
const defaultExpectedOutput =
|
|
'<html><head></head><body><app ng-version="0.0.0-PLACEHOLDER" ng-server-context="other">Works!</app><script id="ng-state" type="application/json">{"test":10}</script></body></html>';
|
|
|
|
it('adds transfer script tag when using renderModule', async () => {
|
|
const STATE_KEY = makeStateKey<number>('test');
|
|
|
|
@Component({selector: 'app', template: 'Works!'})
|
|
class TransferComponent {
|
|
constructor(private transferStore: TransferState) {
|
|
this.transferStore.set(STATE_KEY, 10);
|
|
}
|
|
}
|
|
|
|
@NgModule({
|
|
bootstrap: [TransferComponent],
|
|
declarations: [TransferComponent],
|
|
imports: [BrowserModule, ServerModule],
|
|
})
|
|
class TransferStoreModule {
|
|
}
|
|
|
|
const output = await renderModule(TransferStoreModule, {document: '<app></app>'});
|
|
expect(output).toBe(defaultExpectedOutput);
|
|
});
|
|
|
|
it('cannot break out of <script> tag in serialized output', async () => {
|
|
const STATE_KEY = makeStateKey<string>('testString');
|
|
|
|
@Component({selector: 'esc-app', template: 'Works!'})
|
|
class EscapedComponent {
|
|
constructor(private transferStore: TransferState) {
|
|
this.transferStore.set(STATE_KEY, '</script><script>alert(\'Hello&\' + "World");');
|
|
}
|
|
}
|
|
@NgModule({
|
|
bootstrap: [EscapedComponent],
|
|
declarations: [EscapedComponent],
|
|
imports: [BrowserModule, ServerModule],
|
|
})
|
|
class EscapedTransferStoreModule {
|
|
}
|
|
|
|
const output =
|
|
await renderModule(EscapedTransferStoreModule, {document: '<esc-app></esc-app>'});
|
|
expect(output).toBe(
|
|
'<html><head></head><body><esc-app ng-version="0.0.0-PLACEHOLDER" ng-server-context="other">Works!</esc-app>' +
|
|
'<script id="ng-state" type="application/json">' +
|
|
`{"testString":"\\u003C/script>\\u003Cscript>alert('Hello&' + \\"World\\");"}` +
|
|
'</script></body></html>');
|
|
});
|
|
|
|
it('adds transfer script tag when setting state during onSerialize', async () => {
|
|
const STATE_KEY = makeStateKey<number>('test');
|
|
|
|
@Component({selector: 'app', template: 'Works!'})
|
|
class TransferComponent {
|
|
constructor(private transferStore: TransferState) {
|
|
this.transferStore.onSerialize(STATE_KEY, () => 10);
|
|
}
|
|
}
|
|
|
|
@NgModule({
|
|
bootstrap: [TransferComponent],
|
|
declarations: [TransferComponent],
|
|
imports: [BrowserModule, ServerModule],
|
|
})
|
|
class TransferStoreModule {
|
|
}
|
|
|
|
const output = await renderModule(TransferStoreModule, {document: '<app></app>'});
|
|
expect(output).toBe(defaultExpectedOutput);
|
|
});
|
|
});
|