| 567 | ) |
| 568 | |
| 569 | const fetchModuleViaWebSocket = async (filePath: string) => { |
| 570 | const resolvedPath = path.resolve(root, filePath) |
| 571 | const token = viteServer.config.webSocketToken |
| 572 | const wsUrl = viteTestUrl.replace('http', 'ws') |
| 573 | const ws = new WebSocket(`${wsUrl}?token=${token}`, ['vite-hmr']) |
| 574 | |
| 575 | try { |
| 576 | return await Promise.race([ |
| 577 | new Promise<any>((resolve, reject) => { |
| 578 | ws.on('open', () => { |
| 579 | ws.send( |
| 580 | JSON.stringify({ |
| 581 | type: 'custom', |
| 582 | event: 'vite:invoke', |
| 583 | data: { |
| 584 | name: 'fetchModule', |
| 585 | id: 'send:1', |
| 586 | data: [pathToFileURL(resolvedPath).href], |
| 587 | }, |
| 588 | }), |
| 589 | ) |
| 590 | }) |
| 591 | |
| 592 | ws.on('message', (raw: Buffer) => { |
| 593 | const parsed = JSON.parse(raw.toString()) |
| 594 | if ( |
| 595 | parsed.type === 'custom' && |
| 596 | parsed.event === 'vite:invoke' && |
| 597 | parsed.data?.id === 'response:1' |
| 598 | ) { |
| 599 | resolve(parsed.data.data) |
| 600 | } |
| 601 | }) |
| 602 | |
| 603 | ws.on('error', (err) => { |
| 604 | reject(err) |
| 605 | }) |
| 606 | }), |
| 607 | setTimeout(10_000).then(() => |
| 608 | Promise.reject(new Error('WebSocket response timed out')), |
| 609 | ), |
| 610 | ]) |
| 611 | } finally { |
| 612 | ws.close() |
| 613 | } |
| 614 | } |
| 615 | |
| 616 | test('should not read files inside allowed directories as fetchModule is disabled', async () => { |
| 617 | const result = await fetchModuleViaWebSocket('root/src/safe.txt?raw') |