diff --git a/src/module.ts b/src/module.ts index 30664c4b..c57b784b 100644 --- a/src/module.ts +++ b/src/module.ts @@ -211,12 +211,12 @@ function registerRateLimiterStorage(nuxt: Nuxt, securityOptions: ModuleOptions) securityOptions.rateLimiter ? securityOptions.rateLimiter.driver : undefined, { name: 'lruCache' } ) - const { name, options } = driver + const { name, options = {} } = driver config.storage = defu( { '#rate-limiter-storage': { driver: name, - options + ...options } }, config.storage diff --git a/src/types/middlewares.ts b/src/types/middlewares.ts index 65f85893..b349734b 100644 --- a/src/types/middlewares.ts +++ b/src/types/middlewares.ts @@ -1,16 +1,18 @@ +import type { BuiltinDriverName, BuiltinDriverOptions } from 'unstorage' export type RequestSizeLimiter = { maxRequestSizeInBytes: number; maxUploadFileRequestInBytes: number; throwError?: boolean; }; -export type RateLimiter = { +export type RateLimiter = { tokensPerInterval: number; interval: string | number; driver?: { - name: string, - options?: Record - } + [K in T]: { + name: K; + options?: BuiltinDriverOptions[K] } + }[T]; headers?: boolean; throwError?: boolean; }; diff --git a/test/fixtures/storageOptions/app.vue b/test/fixtures/storageOptions/app.vue new file mode 100644 index 00000000..2b1be090 --- /dev/null +++ b/test/fixtures/storageOptions/app.vue @@ -0,0 +1,5 @@ + diff --git a/test/fixtures/storageOptions/nuxt.config.ts b/test/fixtures/storageOptions/nuxt.config.ts new file mode 100644 index 00000000..7bf373e9 --- /dev/null +++ b/test/fixtures/storageOptions/nuxt.config.ts @@ -0,0 +1,17 @@ +export default defineNuxtConfig({ + modules: [ + '../../../src/module' + ], + security: { + rateLimiter: { + tokensPerInterval: 3, + interval: 1000000, + driver: { + name: 'fsLite', + options: { + base: './test/fixtures/storageOptions/.nuxt/test/.data/db' + } + } + } + } +}) diff --git a/test/fixtures/storageOptions/package.json b/test/fixtures/storageOptions/package.json new file mode 100644 index 00000000..decd4334 --- /dev/null +++ b/test/fixtures/storageOptions/package.json @@ -0,0 +1,5 @@ +{ + "private": true, + "name": "basic", + "type": "module" +} diff --git a/test/fixtures/storageOptions/pages/index.vue b/test/fixtures/storageOptions/pages/index.vue new file mode 100644 index 00000000..8371b274 --- /dev/null +++ b/test/fixtures/storageOptions/pages/index.vue @@ -0,0 +1,3 @@ + diff --git a/test/storageOptions.test.ts b/test/storageOptions.test.ts new file mode 100644 index 00000000..d0aff970 --- /dev/null +++ b/test/storageOptions.test.ts @@ -0,0 +1,36 @@ +import { describe, it, expect } from 'vitest' +import { fileURLToPath } from 'node:url' +import { rm } from 'node:fs/promises' +import { setup, fetch } from '@nuxt/test-utils' + +describe('[nuxt-security] Storage options', async () => { + await setup({ + rootDir: fileURLToPath(new URL('./fixtures/storageOptions', import.meta.url)), + }) + + const dbPath = './test/fixtures/storageOptions/.nuxt/test/.data/db' + await rm(dbPath, { recursive: true, force: true }) + + it('should pass options to a custom driver', async () => { + const res1 = await fetch('/') + const res2 = await fetch('/') + + expect(res1).toBeDefined() + expect(res1).toBeTruthy() + expect(res2.status).toBe(200) + expect(res2.statusText).toBe('OK') + }) + + it('should return 429 with the custom driver', async () => { + const res1 = await fetch('/') + await fetch('/') + await fetch('/') + await fetch('/') + const res5 = await fetch('/') + + expect(res1).toBeDefined() + expect(res1).toBeTruthy() + expect(res5.status).toBe(429) + expect(res5.statusText).toBe('Too Many Requests') + }) +})