Skip to content

Commit

Permalink
fix: sanitize asset filenames (#9737)
Browse files Browse the repository at this point in the history
  • Loading branch information
dominikg committed Aug 19, 2022
1 parent 518bc6c commit 2f468bb
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 1 deletion.
19 changes: 18 additions & 1 deletion packages/vite/src/node/plugins/asset.ts
Expand Up @@ -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}"`
Expand All @@ -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
Expand Down
3 changes: 3 additions & 0 deletions playground/assets-sanitize/+circle.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
27 changes: 27 additions & 0 deletions playground/assets-sanitize/__tests__/assets-sanitize.spec.ts
@@ -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 changes: 3 additions & 0 deletions playground/assets-sanitize/_circle.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions playground/assets-sanitize/index.html
@@ -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 changes: 9 additions & 0 deletions playground/assets-sanitize/index.js
@@ -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 changes: 11 additions & 0 deletions playground/assets-sanitize/package.json
@@ -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 changes: 11 additions & 0 deletions playground/assets-sanitize/vite.config.js
@@ -0,0 +1,11 @@
const { defineConfig } = require('vite')

module.exports = defineConfig({
build: {
//speed up build
minify: false,
target: 'esnext',
assetsInlineLimit: 0,
manifest: true
}
})

0 comments on commit 2f468bb

Please sign in to comment.