mirror of
https://github.com/vitejs/vite.git
synced 2024-11-21 22:59:10 +00:00
fix: sanitize asset filenames (#9737)
This commit is contained in:
parent
518bc6ce99
commit
2f468bb33c
@ -342,7 +342,7 @@ export function assetFileNamesToFileName(
|
||||
return hash
|
||||
|
||||
case '[name]':
|
||||
return name
|
||||
return sanitizeFileName(name)
|
||||
}
|
||||
throw new Error(
|
||||
`invalid placeholder ${placeholder} in assetFileNames "${assetFileNames}"`
|
||||
@ -353,6 +353,23 @@ export function assetFileNamesToFileName(
|
||||
return fileName
|
||||
}
|
||||
|
||||
// taken from https://github.com/rollup/rollup/blob/a8647dac0fe46c86183be8596ef7de25bc5b4e4b/src/utils/sanitizeFileName.ts
|
||||
// https://datatracker.ietf.org/doc/html/rfc2396
|
||||
// eslint-disable-next-line no-control-regex
|
||||
const INVALID_CHAR_REGEX = /[\x00-\x1F\x7F<>*#"{}|^[\]`;?:&=+$,]/g
|
||||
const DRIVE_LETTER_REGEX = /^[a-z]:/i
|
||||
function sanitizeFileName(name: string): string {
|
||||
const match = DRIVE_LETTER_REGEX.exec(name)
|
||||
const driveLetter = match ? match[0] : ''
|
||||
|
||||
// A `:` is only allowed as part of a windows drive letter (ex: C:\foo)
|
||||
// Otherwise, avoid them because they can refer to NTFS alternate data streams.
|
||||
return (
|
||||
driveLetter +
|
||||
name.substr(driveLetter.length).replace(INVALID_CHAR_REGEX, '_')
|
||||
)
|
||||
}
|
||||
|
||||
export const publicAssetUrlCache = new WeakMap<
|
||||
ResolvedConfig,
|
||||
// hash -> url
|
||||
|
3
playground/assets-sanitize/+circle.svg
Normal file
3
playground/assets-sanitize/+circle.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="12" cy="12" r="10" fill="#000"></circle>
|
||||
</svg>
|
After Width: | Height: | Size: 135 B |
27
playground/assets-sanitize/__tests__/assets-sanitize.spec.ts
Normal file
27
playground/assets-sanitize/__tests__/assets-sanitize.spec.ts
Normal file
@ -0,0 +1,27 @@
|
||||
import { expect, test } from 'vitest'
|
||||
import { getBg, isBuild, page, readManifest } from '~utils'
|
||||
|
||||
if (!isBuild) {
|
||||
test('importing asset with special char in filename works in dev', async () => {
|
||||
expect(await getBg('.plus-circle')).toContain('+circle.svg')
|
||||
expect(await page.textContent('.plus-circle')).toMatch('+circle.svg')
|
||||
expect(await getBg('.underscore-circle')).toContain('_circle.svg')
|
||||
expect(await page.textContent('.underscore-circle')).toMatch('_circle.svg')
|
||||
})
|
||||
} else {
|
||||
test('importing asset with special char in filename works in build', async () => {
|
||||
const manifest = readManifest()
|
||||
const plusCircleAsset = manifest['+circle.svg'].file
|
||||
const underscoreCircleAsset = manifest['_circle.svg'].file
|
||||
expect(await getBg('.plus-circle')).toMatch(plusCircleAsset)
|
||||
expect(await page.textContent('.plus-circle')).toMatch(plusCircleAsset)
|
||||
expect(await getBg('.underscore-circle')).toMatch(underscoreCircleAsset)
|
||||
expect(await page.textContent('.underscore-circle')).toMatch(
|
||||
underscoreCircleAsset
|
||||
)
|
||||
expect(plusCircleAsset).toMatch('/_circle')
|
||||
expect(underscoreCircleAsset).toMatch('/_circle')
|
||||
expect(plusCircleAsset).not.toEqual(underscoreCircleAsset)
|
||||
expect(Object.keys(manifest).length).toBe(3) // 2 svg, 1 index.js
|
||||
})
|
||||
}
|
3
playground/assets-sanitize/_circle.svg
Normal file
3
playground/assets-sanitize/_circle.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle cx="12" cy="12" r="10" fill="red"></circle>
|
||||
</svg>
|
After Width: | Height: | Size: 134 B |
11
playground/assets-sanitize/index.html
Normal file
11
playground/assets-sanitize/index.html
Normal file
@ -0,0 +1,11 @@
|
||||
<script type="module" src="./index.js"></script>
|
||||
<style>
|
||||
.test-el {
|
||||
background-repeat: no-repeat;
|
||||
padding-left: 2rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
</style>
|
||||
<h1>test elements below should show circles and their url</h1>
|
||||
<div class="test-el plus-circle"></div>
|
||||
<div class="test-el underscore-circle"></div>
|
9
playground/assets-sanitize/index.js
Normal file
9
playground/assets-sanitize/index.js
Normal file
@ -0,0 +1,9 @@
|
||||
import plusCircle from './+circle.svg'
|
||||
import underscoreCircle from './_circle.svg'
|
||||
function setData(classname, file) {
|
||||
const el = document.body.querySelector(classname)
|
||||
el.style.backgroundImage = `url(${file})`
|
||||
el.textContent = file
|
||||
}
|
||||
setData('.plus-circle', plusCircle)
|
||||
setData('.underscore-circle', underscoreCircle)
|
11
playground/assets-sanitize/package.json
Normal file
11
playground/assets-sanitize/package.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "test-assets-sanitize",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"debug": "node --inspect-brk ../../packages/vite/bin/vite",
|
||||
"preview": "vite preview"
|
||||
}
|
||||
}
|
11
playground/assets-sanitize/vite.config.js
Normal file
11
playground/assets-sanitize/vite.config.js
Normal file
@ -0,0 +1,11 @@
|
||||
const { defineConfig } = require('vite')
|
||||
|
||||
module.exports = defineConfig({
|
||||
build: {
|
||||
//speed up build
|
||||
minify: false,
|
||||
target: 'esnext',
|
||||
assetsInlineLimit: 0,
|
||||
manifest: true
|
||||
}
|
||||
})
|
Loading…
Reference in New Issue
Block a user