From 054a4561ae14f23b9bfcf3e8c06fd50a2f8ef6b6 Mon Sep 17 00:00:00 2001 From: Vincent Ricard Date: Sat, 30 Jan 2021 21:38:52 +0100 Subject: [PATCH] Add option to filter files --- README.md | 8 ++++++++ index.d.ts | 1 + index.js | 6 ++++++ test/static.test.js | 42 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+) diff --git a/README.md b/README.md index e177847..4365612 100644 --- a/README.md +++ b/README.md @@ -135,6 +135,14 @@ for getting the file list. This option cannot be set to `false` with `redirect` set to `true` on a server with `ignoreTrailingSlash` set to `true`. +#### `allowedPath` + +Default: `(pathname, root) => true` + +This function allows filtering the served files. +If the function returns `true`, the file will be served. +If the function returns `false`, Fastify's 404 handler will be called. + #### `list` Default: `undefined` diff --git a/index.d.ts b/index.d.ts index 73a9ff8..cefcda0 100644 --- a/index.d.ts +++ b/index.d.ts @@ -41,6 +41,7 @@ export interface FastifyStaticOptions { redirect?: boolean; wildcard?: boolean | string; list?: boolean | ListOptions; + allowedPath?: (pathName: string, root?: string) => boolean; // Passed on to `send` acceptRanges?: boolean; diff --git a/index.js b/index.js index 2edad46..d17f74d 100644 --- a/index.js +++ b/index.js @@ -39,6 +39,8 @@ async function fastifyStatic (fastify, opts) { maxAge: opts.maxAge } + const allowedPath = opts.allowedPath + function pumpSendToReply (request, reply, pathname, rootPath, rootPathOffset = 0) { const options = Object.assign({}, sendOptions) @@ -50,6 +52,10 @@ async function fastifyStatic (fastify, opts) { } } + if (allowedPath && !allowedPath(pathname, options.root)) { + return reply.callNotFound() + } + const stream = send(request.raw, pathname, options) let resolvedFilename stream.on('file', function (file) { diff --git a/test/static.test.js b/test/static.test.js index 88b931e..4e021f0 100644 --- a/test/static.test.js +++ b/test/static.test.js @@ -819,6 +819,48 @@ t.test('sendFile disabled', t => { }) }) +t.test('allowedPath option', t => { + t.plan(3) + + const pluginOptions = { + root: path.join(__dirname, '/static'), + allowedPath: (pathName) => pathName !== '/foobar.html' + } + const fastify = Fastify() + fastify.register(fastifyStatic, pluginOptions) + + fastify.listen(0, err => { + t.error(err) + + fastify.server.unref() + + t.test('/foobar.html not found', t => { + t.plan(2 + GENERIC_ERROR_RESPONSE_CHECK_COUNT) + simple.concat({ + method: 'GET', + url: 'http://localhost:' + fastify.server.address().port + '/foobar.html', + followRedirect: false + }, (err, response, body) => { + t.error(err) + t.strictEqual(response.statusCode, 404) + genericErrorResponseChecks(t, response) + }) + }) + + t.test('/index.css found', t => { + t.plan(2) + simple.concat({ + method: 'GET', + url: 'http://localhost:' + fastify.server.address().port + '/index.css', + followRedirect: false + }, (err, response, body) => { + t.error(err) + t.strictEqual(response.statusCode, 200) + }) + }) + }) +}) + t.test('prefix default', t => { t.plan(1) const pluginOptions = { root: path.join(__dirname, 'static') }