From 8a52c7660bc5e505283665310ac49415ae3d9cbf Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Wed, 26 Jul 2023 13:01:06 +0200 Subject: [PATCH 1/4] add channelOptions so serverChannel doesn't try to parse functions or classes --- code/lib/core-server/src/utils/get-server-channel.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/code/lib/core-server/src/utils/get-server-channel.ts b/code/lib/core-server/src/utils/get-server-channel.ts index c44c51b36307..9d6de688f521 100644 --- a/code/lib/core-server/src/utils/get-server-channel.ts +++ b/code/lib/core-server/src/utils/get-server-channel.ts @@ -27,7 +27,10 @@ export class ServerChannelTransport { this.socket.on('connection', (wss) => { wss.on('message', (raw) => { const data = raw.toString(); - const event = typeof data === 'string' && isJSON(data) ? parse(data) : data; + const event = + typeof data === 'string' && isJSON(data) + ? parse(data, { allowFunction: false, allowClass: false }) + : data; this.handler?.(event); }); }); From 154f6cbde5638d90202480ae5fa9e8c8c5a82ded Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Wed, 26 Jul 2023 13:18:21 +0200 Subject: [PATCH 2/4] not pass fn & classes to serverChannel --- code/lib/core-server/src/utils/get-server-channel.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/lib/core-server/src/utils/get-server-channel.ts b/code/lib/core-server/src/utils/get-server-channel.ts index 9d6de688f521..1a488afb06c9 100644 --- a/code/lib/core-server/src/utils/get-server-channel.ts +++ b/code/lib/core-server/src/utils/get-server-channel.ts @@ -41,7 +41,7 @@ export class ServerChannelTransport { } send(event: any) { - const data = stringify(event, { maxDepth: 15, allowFunction: true }); + const data = stringify(event, { maxDepth: 15, allowFunction: false, allowClass: false }); Array.from(this.socket.clients) .filter((c) => c.readyState === WebSocket.OPEN) From 08de34d67fdfaa3722d7b35c9cf7cd885b52954e Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Thu, 27 Jul 2023 16:33:51 +0200 Subject: [PATCH 3/4] add test --- .../utils/__tests__/server-channel.test.ts | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 code/lib/core-server/src/utils/__tests__/server-channel.test.ts diff --git a/code/lib/core-server/src/utils/__tests__/server-channel.test.ts b/code/lib/core-server/src/utils/__tests__/server-channel.test.ts new file mode 100644 index 000000000000..79c4d3020a41 --- /dev/null +++ b/code/lib/core-server/src/utils/__tests__/server-channel.test.ts @@ -0,0 +1,86 @@ +import type { Server } from 'http'; +import { Channel } from '@storybook/channels'; + +import { EventEmitter } from 'events'; +import { stringify } from 'telejson'; +import { getServerChannel, ServerChannelTransport } from '../get-server-channel'; + +describe('getServerChannel', () => { + test('should return a channel', () => { + const server = { on: jest.fn() } as any as Server; + const result = getServerChannel(server); + expect(result).toBeInstanceOf(Channel); + }); + + test('should attach to the http server', () => { + const server = { on: jest.fn() } as any as Server; + getServerChannel(server); + expect(server.on).toHaveBeenCalledWith('upgrade', expect.any(Function)); + }); +}); + +describe('ServerChannelTransport', () => { + test('parses simple JSON', () => { + const server = new EventEmitter() as any as Server; + const socket = new EventEmitter(); + const transport = new ServerChannelTransport(server); + const handler = jest.fn(); + transport.setHandler(handler); + + // @ts-expect-error (an internal API) + transport.socket.emit('connection', socket); + socket.emit('message', '"hello"'); + + expect(handler).toHaveBeenCalledWith('hello'); + }); + test('parses object JSON', () => { + const server = new EventEmitter() as any as Server; + const socket = new EventEmitter(); + const transport = new ServerChannelTransport(server); + const handler = jest.fn(); + transport.setHandler(handler); + + // @ts-expect-error (an internal API) + transport.socket.emit('connection', socket); + socket.emit('message', JSON.stringify({ type: 'hello' })); + + expect(handler).toHaveBeenCalledWith({ type: 'hello' }); + }); + test('supports telejson cyclical data', () => { + const server = new EventEmitter() as any as Server; + const socket = new EventEmitter(); + const transport = new ServerChannelTransport(server); + const handler = jest.fn(); + transport.setHandler(handler); + + // @ts-expect-error (an internal API) + transport.socket.emit('connection', socket); + + const input = { a: 1 }; + input.b = input; + socket.emit('message', stringify(input)); + + expect(handler.mock.calls[0][0]).toMatchInlineSnapshot(` + Object { + "a": 1, + "b": [Circular], + } + `); + }); + test('skips telejson classes and functions in data', () => { + const server = new EventEmitter() as any as Server; + const socket = new EventEmitter(); + const transport = new ServerChannelTransport(server); + const handler = jest.fn(); + transport.setHandler(handler); + + // @ts-expect-error (an internal API) + transport.socket.emit('connection', socket); + + const input = { a() {}, b: class {} }; + socket.emit('message', stringify(input)); + + expect(handler.mock.calls[0][0].a).toEqual(expect.any(String)); + expect(handler.mock.calls[0][0].b).toEqual(expect.any(String)); + }); +}); From ff13ab9dd8f52c20bccdb462e79bb8b6c2230636 Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Thu, 27 Jul 2023 16:52:22 +0200 Subject: [PATCH 4/4] typescript ... --- code/lib/core-server/src/utils/__tests__/server-channel.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/lib/core-server/src/utils/__tests__/server-channel.test.ts b/code/lib/core-server/src/utils/__tests__/server-channel.test.ts index 79c4d3020a41..786370be0f99 100644 --- a/code/lib/core-server/src/utils/__tests__/server-channel.test.ts +++ b/code/lib/core-server/src/utils/__tests__/server-channel.test.ts @@ -56,7 +56,7 @@ describe('ServerChannelTransport', () => { // @ts-expect-error (an internal API) transport.socket.emit('connection', socket); - const input = { a: 1 }; + const input: any = { a: 1 }; input.b = input; socket.emit('message', stringify(input));