Skip to content

Commit de438ad

Browse files
committed
BREAKING CHANGE: [#0] Changes JavaScript evaluation to be disabled by default
1 parent c80a08f commit de438ad

File tree

59 files changed

+1304
-644
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

59 files changed

+1304
-644
lines changed

integration-test/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"access": "restricted"
1111
},
1212
"scripts": {
13-
"test": "cd ./test && ls | node --test && node ./browser-exception-observer/BrowserExceptionObserver.test.js",
13+
"test": "cd ./test && ls | node --disallow-code-generation-from-strings --test && node --disallow-code-generation-from-strings ./browser-exception-observer/BrowserExceptionObserver.test.js",
1414
"test:debug": "cd ./test && ls | node --inspect-brk"
1515
},
1616
"devDependencies": {

integration-test/test/Browser.test.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ describe('Browser', () => {
77
const browser = new Browser({
88
settings: {
99
errorCapture: BrowserErrorCaptureEnum.processLevel,
10+
enableJavaScriptEvaluation: true,
1011

1112
// Github.com has a timer that is very long (hours) and a timer loop that never ends.
1213
timer: {
@@ -47,7 +48,8 @@ describe('Browser', () => {
4748
it('Goes to "npmjs.com".', async () => {
4849
const browser = new Browser({
4950
settings: {
50-
errorCapture: BrowserErrorCaptureEnum.processLevel
51+
errorCapture: BrowserErrorCaptureEnum.processLevel,
52+
enableJavaScriptEvaluation: true
5153
}
5254
});
5355
const page = browser.newPage();

integration-test/test/WindowGlobals.test.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { describe, it } from 'node:test';
44

55
describe('WindowGlobals', () => {
66
it('Functions should have the constructor global.Function.', () => {
7-
const window = new Window();
7+
const window = new Window({ settings: { enableJavaScriptEvaluation: true } });
88
let error = null;
99
window.addEventListener('error', (event) => (error = event.error));
1010
window.document.write(`
@@ -18,7 +18,7 @@ describe('WindowGlobals', () => {
1818
});
1919

2020
it('Object should have the constructor global.Object.', () => {
21-
const window = new Window();
21+
const window = new Window({ settings: { enableJavaScriptEvaluation: true } });
2222
let error = null;
2323
window.addEventListener('error', (event) => (error = event.error));
2424
window.document.write(`
@@ -32,7 +32,7 @@ describe('WindowGlobals', () => {
3232
});
3333

3434
it('Binds global methods to the Window context.', () => {
35-
const window = new Window();
35+
const window = new Window({ settings: { enableJavaScriptEvaluation: true } });
3636
let error = null;
3737
window.addEventListener('error', (event) => (error = event.error));
3838
window.document.write(`

integration-test/test/browser-exception-observer/BrowserExceptionObserver.test.js

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ await describe('BrowserExceptionObserver', async () => {
2121
await describe('observe()', async () => {
2222
await it('Observes unhandled fetch rejections.', async () => {
2323
const browser = new Browser({
24-
settings: { errorCapture: BrowserErrorCaptureEnum.processLevel }
24+
settings: {
25+
errorCapture: BrowserErrorCaptureEnum.processLevel,
26+
enableJavaScriptEvaluation: true
27+
}
2528
});
2629
const page = browser.newPage();
2730
const window = page.mainFrame.window;
@@ -58,7 +61,10 @@ await describe('BrowserExceptionObserver', async () => {
5861

5962
await it('Observes uncaught exceptions.', async () => {
6063
const browser = new Browser({
61-
settings: { errorCapture: BrowserErrorCaptureEnum.processLevel }
64+
settings: {
65+
errorCapture: BrowserErrorCaptureEnum.processLevel,
66+
enableJavaScriptEvaluation: true
67+
}
6268
});
6369
const page = browser.newPage();
6470
const window = page.mainFrame.window;

packages/@happy-dom/server-renderer/src/ServerRenderer.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ export default class ServerRenderer {
197197
return;
198198
}
199199
const worker = new Worker(new URL('ServerRendererWorker.js', import.meta.url), {
200+
execArgv: ['--disallow-code-generation-from-strings'],
200201
workerData: {
201202
configuration: configuration
202203
}

packages/@happy-dom/server-renderer/src/config/DefaultServerRendererConfiguration.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,13 @@ import OS from 'os';
55
import { BrowserErrorCaptureEnum } from 'happy-dom';
66

77
export default <IServerRendererConfiguration>{
8-
browser: { ...DefaultBrowserSettings, errorCapture: BrowserErrorCaptureEnum.processLevel },
8+
browser: {
9+
...DefaultBrowserSettings,
10+
errorCapture: BrowserErrorCaptureEnum.processLevel,
11+
// This is enabled by default as the entire point of this package is to server-render client side JavaScript.
12+
// "--disallow-code-generation-from-strings" is enabled on workers to prevent escape of the VM context.
13+
enableJavaScriptEvaluation: true
14+
},
915
outputDirectory: './happy-dom/render',
1016
logLevel: ServerRendererLogLevelEnum.info,
1117
debug: false,

packages/@happy-dom/server-renderer/src/utilities/HelpPrinterRows.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,12 +126,19 @@ export default [
126126
'1'
127127
],
128128
[
129-
'--browser.disableJavascriptEvaluation',
129+
'--browser.disableJavaScriptEvaluation',
130130
'',
131131
'boolean',
132132
'Disables JavaScript evaluation.',
133133
'false'
134134
],
135+
[
136+
'--browser.suppressCodeGenerationFromStringsWarning',
137+
'',
138+
'boolean',
139+
'Suppresses the warning that is printed when code generation from strings is enabled at process level',
140+
'false'
141+
],
135142
[
136143
'--browser.disableJavaScriptFileLoading',
137144
'',

packages/@happy-dom/server-renderer/src/utilities/ProcessArgumentsParser.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,9 @@ export default class ProcessArgumentsParser {
4040
} else if (arg === '--help' || arg === '-h') {
4141
config.help = true;
4242
} else if (arg === '--browser.disableJavaScriptEvaluation') {
43-
config.browser.disableJavaScriptEvaluation = true;
43+
config.browser.enableJavaScriptEvaluation = false;
44+
} else if (arg === '--browser.suppressCodeGenerationFromStringsWarning') {
45+
config.browser.suppressCodeGenerationFromStringsWarning = true;
4446
} else if (arg === '--browser.disableJavaScriptFileLoading') {
4547
config.browser.disableJavaScriptFileLoading = true;
4648
} else if (arg === '--browser.disableCSSFileLoading') {

packages/@happy-dom/server-renderer/test/MockedWorker.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@ import IServerRendererConfiguration from '../src/types/IServerRendererConfigurat
22
import IServerRendererItem from '../src/types/IServerRendererItem';
33
import IServerRendererResult from '../src/types/IServerRendererResult';
44

5+
type TEvent = 'message' | 'error' | 'exit';
6+
57
/**
6-
*
8+
* Mocked worker.
79
*/
810
export default class MockedWorker {
911
public static openWorkers: MockedWorker[] = [];
1012
public static terminatedWorkers: MockedWorker[] = [];
1113
public scriptPath: string;
14+
public execArgv: string[] = [];
1215
public workerData: {
1316
configuration: IServerRendererConfiguration;
1417
};
@@ -25,13 +28,16 @@ export default class MockedWorker {
2528
public isTerminated: boolean = false;
2629

2730
/**
31+
* Constructor.
2832
*
29-
* @param scriptPath
30-
* @param options
31-
* @param options.workerData
33+
* @param scriptPath Script path.
34+
* @param options Options.
35+
* @param options.execArgv Exec arguments.
36+
* @param options.workerData Worker data.
3237
*/
33-
constructor(scriptPath: string, options: { workerData: any }) {
38+
constructor(scriptPath: string, options: { execArgv: string[]; workerData: any }) {
3439
this.scriptPath = scriptPath;
40+
this.execArgv = options.execArgv;
3541
this.workerData = options.workerData;
3642
(<typeof MockedWorker>this.constructor).openWorkers.push(this);
3743
}
@@ -41,7 +47,7 @@ export default class MockedWorker {
4147
* @param event
4248
* @param listener
4349
*/
44-
public on(event: string, listener: any): void {
50+
public on(event: TEvent, listener: any): void {
4551
this.listeners[event].push(listener);
4652
}
4753

@@ -50,7 +56,7 @@ export default class MockedWorker {
5056
* @param event
5157
* @param listener
5258
*/
53-
public off(event: string, listener: any): void {
59+
public off(event: TEvent, listener: any): void {
5460
const index = this.listeners[event].indexOf(listener);
5561
this.listeners[event].splice(index, 1);
5662
}

packages/@happy-dom/server-renderer/test/ServerRenderer.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ describe('ServerRenderer', () => {
5858
'file://' + Path.resolve(Path.join('src', 'ServerRendererWorker.js'))
5959
);
6060

61+
expect(worker.execArgv).toEqual(['--disallow-code-generation-from-strings']);
62+
6163
expect(worker.workerData.configuration.cache.directory).toBe(
6264
Path.resolve(Path.join('happy-dom', 'cache'))
6365
);
@@ -214,6 +216,8 @@ describe('ServerRenderer', () => {
214216
'file://' + Path.resolve(Path.join('src', 'ServerRendererWorker.js'))
215217
);
216218

219+
expect(worker.execArgv).toEqual(['--disallow-code-generation-from-strings']);
220+
217221
expect(worker.workerData.configuration.cache.directory).toBe(
218222
Path.resolve(Path.join('happy-dom', 'cache'))
219223
);

0 commit comments

Comments
 (0)