Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: server.fs.deny support #5378

Merged
merged 5 commits into from Oct 27, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 9 additions & 0 deletions docs/config/index.md
Expand Up @@ -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`
Expand Down
8 changes: 8 additions & 0 deletions packages/playground/fs-serve/__tests__/fs-serve.spec.ts
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion packages/playground/fs-serve/root/src/.env
@@ -1 +1 @@
KEY=safe
KEY=unsafe
18 changes: 15 additions & 3 deletions packages/playground/fs-serve/root/src/index.html
Expand Up @@ -23,6 +23,9 @@ <h2>Unsafe /@fs/ Fetch</h2>
<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'
Expand All @@ -31,7 +34,7 @@ <h2>Nested Entry</h2>
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()
Expand All @@ -41,7 +44,7 @@ <h2>Nested Entry</h2>
})

// outside of allowed dir, treated as unsafe
fetch('/.env')
fetch('/unsafe.txt')
.then((r) => {
text('.unsafe-fetch-status', r.status)
return r.text()
Expand Down Expand Up @@ -76,7 +79,16 @@ <h2>Nested Entry</h2>
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>
1 change: 1 addition & 0 deletions packages/playground/fs-serve/root/src/safe.txt
@@ -0,0 +1 @@
KEY=safe
16 changes: 15 additions & 1 deletion packages/vite/src/node/server/index.ts
Expand Up @@ -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[]
}

/**
Expand Down Expand Up @@ -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)]
Expand All @@ -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
}
6 changes: 6 additions & 0 deletions packages/vite/src/node/server/middlewares/static.ts
Expand Up @@ -14,6 +14,7 @@ import {
slash,
isFileReadable
} from '../../utils'
import match from 'minimatch'

const sirvOptions: Options = {
dev: true,
Expand Down Expand Up @@ -130,6 +131,8 @@ export function serveRawFsMiddleware(
}
}

const _matchOptions = { matchBase: true }

export function isFileServingAllowed(
url: string,
server: ViteDevServer
Expand All @@ -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 + '/')))
Expand Down
6 changes: 5 additions & 1 deletion packages/vite/types/shims.d.ts
Expand Up @@ -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
}

Expand Down