Skip to content

Commit

Permalink
fix: backport #7317 to v1 (#7319)
Browse files Browse the repository at this point in the history
Co-authored-by: Ari Perkkiö <ari.perkkio@gmail.com>
  • Loading branch information
hi-ogawa and AriPerkkio authored Feb 2, 2025
1 parent 73cb696 commit 7ce9fbb
Show file tree
Hide file tree
Showing 18 changed files with 2,541 additions and 1,083 deletions.
2 changes: 0 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ on:
- main

pull_request:
branches:
- main

concurrency:
group: ci-${{ github.event.pull_request.number || github.ref }}
Expand Down
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
"devDependencies": {
"@antfu/eslint-config": "^2.15.0",
"@antfu/ni": "^0.21.12",
"@playwright/test": "^1.41.0",
"@playwright/test": "^1.49.1",
"@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-json": "^6.0.1",
"@rollup/plugin-node-resolve": "^15.2.3",
Expand Down Expand Up @@ -70,6 +70,8 @@
},
"pnpm": {
"overrides": {
"@vitest/browser": "$@vitest/browser",
"@vitest/ui": "$@vitest/ui",
"rollup": "$rollup",
"vite": "$vite",
"vitest": "workspace:*"
Expand Down
2 changes: 1 addition & 1 deletion packages/browser/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@
"@vitest/ws-client": "workspace:*",
"@wdio/protocols": "^8.29.7",
"periscopic": "^4.0.2",
"playwright": "^1.41.0",
"playwright": "^1.49.1",
"playwright-core": "^1.41.0",
"safaridriver": "^0.1.2",
"vitest": "workspace:*",
Expand Down
2 changes: 1 addition & 1 deletion packages/browser/src/client/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export const PORT = import.meta.hot ? '51204' : location.port
export const HOST = [location.hostname, PORT].filter(Boolean).join(':')
export const ENTRY_URL = `${
location.protocol === 'https:' ? 'wss:' : 'ws:'
}//${HOST}/__vitest_api__`
}//${HOST}/__vitest_api__?token=${(window as any).VITEST_API_TOKEN}`

let setCancel = (_: CancelReason) => {}
export const onCancel = new Promise<CancelReason>((resolve) => {
Expand Down
1 change: 1 addition & 0 deletions packages/browser/src/client/public/esm-client-injector.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ window.__vitest_browser_runner__ = {
config: { __VITEST_CONFIG__ },
files: { __VITEST_FILES__ },
}
window.VITEST_API_TOKEN = { __VITEST_API_TOKEN__ }

const config = __vitest_browser_runner__.config

Expand Down
1 change: 1 addition & 0 deletions packages/browser/src/node/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export default (project: WorkspaceProject, base = '/'): Plugin[] => {
const injector = replacer(await injectorJs, {
__VITEST_CONFIG__: JSON.stringify(config),
__VITEST_FILES__: JSON.stringify(files),
__VITEST_API_TOKEN__: JSON.stringify(project.ctx.config.api.token),
})

if (url.pathname === base) {
Expand Down
2 changes: 1 addition & 1 deletion packages/ui/client/constants.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export const PORT = import.meta.hot ? '51204' : location.port
export const HOST = [location.hostname, PORT].filter(Boolean).join(':')
export const ENTRY_URL = `${location.protocol === 'https:' ? 'wss:' : 'ws:'}//${HOST}/__vitest_api__`
export const ENTRY_URL = `${location.protocol === 'https:' ? 'wss:' : 'ws:'}//${HOST}/__vitest_api__?token=${(window as any).VITEST_API_TOKEN}`
export const isReport = !!window.METADATA_PATH
export const BASE_PATH = isReport ? import.meta.env.BASE_URL : __BASE_PATH__
22 changes: 22 additions & 0 deletions packages/ui/node/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import fs from 'node:fs'
import { fileURLToPath } from 'node:url'
import { basename, resolve } from 'pathe'
import sirv from 'sirv'
Expand Down Expand Up @@ -25,6 +26,27 @@ export default (ctx: Vitest): Plugin => {
},
}))
const clientDist = resolve(fileURLToPath(import.meta.url), '../client')
const clientIndexHtml = fs.readFileSync(resolve(clientDist, 'index.html'), 'utf-8')

// serve index.html with api token
server.middlewares.use((req, res, next) => {
if (req.url) {
const url = new URL(req.url, 'http://localhost')
if (url.pathname === base) {
const html = clientIndexHtml.replace(
'<!-- !LOAD_METADATA! -->',
`<script>window.VITEST_API_TOKEN = ${JSON.stringify(ctx.config.api.token)}</script>`,
)
res.setHeader('Cache-Control', 'no-cache, max-age=0, must-revalidate')
res.setHeader('Content-Type', 'text/html; charset=utf-8')
res.write(html)
res.end()
return
}
}
next()
})

server.middlewares.use(base, sirv(clientDist, {
single: true,
dev: true,
Expand Down
1 change: 1 addition & 0 deletions packages/vitest/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ const external = [
'node:fs',
'node:stream',
'node:vm',
'node:http',
'inspector',
'vite-node/source-map',
'vite-node/client',
Expand Down
21 changes: 21 additions & 0 deletions packages/vitest/src/api/check.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { IncomingMessage } from 'node:http'
import crypto from 'node:crypto'
import type { ResolvedConfig } from '../types/config'

export function isValidApiRequest(config: ResolvedConfig, req: IncomingMessage): boolean {
const url = new URL(req.url ?? '', 'http://localhost')

// validate token. token is injected in ui/tester/orchestrator html, which is cross origin proteced.
try {
const token = url.searchParams.get('token')
if (token && crypto.timingSafeEqual(
Buffer.from(token),
Buffer.from(config.api.token),
))
return true
}
// an error is thrown when the length is incorrect
catch {}

return false
}
6 changes: 6 additions & 0 deletions packages/vitest/src/api/setup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { getModuleGraph, isPrimitive, noop, stringifyReplace } from '../utils'
import type { WorkspaceProject } from '../node/workspace'
import { parseErrorStacktrace } from '../utils/source-map'
import type { TransformResultWithSource, WebSocketEvents, WebSocketHandlers } from './types'
import { isValidApiRequest } from './check'

export function setup(vitestOrWorkspace: Vitest | WorkspaceProject, _server?: ViteDevServer) {
const ctx = 'ctx' in vitestOrWorkspace ? vitestOrWorkspace.ctx : vitestOrWorkspace
Expand All @@ -34,6 +35,11 @@ export function setup(vitestOrWorkspace: Vitest | WorkspaceProject, _server?: Vi
if (pathname !== API_PATH)
return

if (!isValidApiRequest(ctx.config, request)) {
socket.destroy()
return
}

wss.handleUpgrade(request, socket, head, (ws) => {
wss.emit('connection', ws, request)
setupClient(ws)
Expand Down
4 changes: 3 additions & 1 deletion packages/vitest/src/node/config.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import crypto from 'node:crypto'
import { resolveModule } from 'local-pkg'
import { normalize, relative, resolve } from 'pathe'
import c from 'picocolors'
Expand Down Expand Up @@ -408,7 +409,8 @@ export function resolveConfig(
}

// the server has been created, we don't need to override vite.server options
resolved.api = resolveApiServerConfig(options)
const api = resolveApiServerConfig(options)
resolved.api = { ...api, token: crypto.randomUUID() }

if (options.related)
resolved.related = toArray(options.related).map(file => resolve(resolved.root, file))
Expand Down
2 changes: 1 addition & 1 deletion packages/vitest/src/types/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -894,7 +894,7 @@ export interface ResolvedConfig extends Omit<Required<UserConfig>, 'config' | 'f

defines: Record<string, any>

api?: ApiConfig
api: ApiConfig & { token: string }
cliExclude?: string[]

benchmark?: Required<Omit<BenchmarkUserOptions, 'outputFile' | 'compare' | 'outputJson'>> & Pick<BenchmarkUserOptions, 'outputFile' | 'compare' | 'outputJson'>
Expand Down
Loading

0 comments on commit 7ce9fbb

Please sign in to comment.