feat: server.fs.deny support (#5378)

This commit is contained in:
Anthony Fu 2021-10-27 22:32:15 +08:00 committed by GitHub
parent d5e51f4840
commit 1a15460bf3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 60 additions and 6 deletions

View File

@ -593,6 +593,15 @@ createServer()
})
```
### server.fs.deny
- **Experimental**
- **Type:** `string[]`
Blocklist for sensitive files being restricted to be served by Vite dev server.
Default to `['.env', '.env.*', '*.{pem,crt}']`.
### server.origin
- **Type:** `string`

View File

@ -41,6 +41,14 @@ describe('main', () => {
test('nested entry', async () => {
expect(await page.textContent('.nested-entry')).toBe('foobar')
})
test('nested entry', async () => {
expect(await page.textContent('.nested-entry')).toBe('foobar')
})
test('denied', async () => {
expect(await page.textContent('.unsafe-dotenv')).toBe('404')
})
} else {
test('dummy test to make jest happy', async () => {
// Your test suite must contain at least one test.

View File

@ -1 +1 @@
KEY=safe
KEY=unsafe

View File

@ -23,6 +23,9 @@
<h2>Nested Entry</h2>
<pre class="nested-entry"></pre>
<h2>Denied</h2>
<pre class="unsafe-dotenv"></pre>
<script type="module">
import '../../entry'
import json, { msg } from '../../safe.json'
@ -31,7 +34,7 @@
text('.named', msg)
// inside allowed dir, safe fetch
fetch('/src/.env')
fetch('/src/safe.txt')
.then((r) => {
text('.safe-fetch-status', r.status)
return r.text()
@ -41,7 +44,7 @@
})
// outside of allowed dir, treated as unsafe
fetch('/.env')
fetch('/unsafe.txt')
.then((r) => {
text('.unsafe-fetch-status', r.status)
return r.text()
@ -76,7 +79,16 @@
console.error(e)
})
// .env, denied by default
fetch('/@fs/' + ROOT + '/root/.env')
.then((r) => {
text('.unsafe-dotenv', r.status)
})
.catch((e) => {
console.error(e)
})
function text(sel, text) {
document.querySelector(sel).textContent = text
}
</script>
</script>

View File

@ -0,0 +1 @@
KEY=safe

View File

@ -162,6 +162,18 @@ export interface FileSystemServeOptions {
* @experimental
*/
allow?: string[]
/**
* Restrict accessing files that matches the patterns.
*
* This will have higher priority than `allow`.
* Glob patterns are supported.
*
* @default ['.env', '.env.*', '*.crt', '*.pem']
*
* @experimental
*/
deny?: string[]
}
/**
@ -690,6 +702,7 @@ export function resolveServerOptions(
): ResolvedServerOptions {
const server = raw || {}
let allowDirs = server.fs?.allow
const deny = server.fs?.deny || ['.env', '.env.*', '*.{crt,pem}']
if (!allowDirs) {
allowDirs = [searchForWorkspaceRoot(root)]
@ -706,7 +719,8 @@ export function resolveServerOptions(
server.fs = {
// TODO: make strict by default
strict: server.fs?.strict,
allow: allowDirs
allow: allowDirs,
deny
}
return server as ResolvedServerOptions
}

View File

@ -14,6 +14,7 @@ import {
slash,
isFileReadable
} from '../../utils'
import match from 'minimatch'
const sirvOptions: Options = {
dev: true,
@ -130,6 +131,8 @@ export function serveRawFsMiddleware(
}
}
const _matchOptions = { matchBase: true }
export function isFileServingAllowed(
url: string,
server: ViteDevServer
@ -140,6 +143,9 @@ export function isFileServingAllowed(
const cleanedUrl = cleanUrl(url)
const file = ensureLeadingSlash(normalizePath(cleanedUrl))
if (server.config.server.fs.deny.some((i) => match(file, i, _matchOptions)))
return false
if (server.moduleGraph.safeModulesPath.has(file)) return true
if (server.config.server.fs.allow.some((i) => file.startsWith(i + '/')))

View File

@ -96,7 +96,11 @@ declare module 'rollup-plugin-web-worker-loader' {
}
declare module 'minimatch' {
function match(path: string, pattern: string): boolean
function match(
path: string,
pattern: string,
options?: { matchBase?: boolean }
): boolean
export default match
}