Files
order_site/security-artifacts/BASELINE_rate-limit.test.ts
T

114 lines
2.6 KiB
TypeScript

import test from 'node:test'
import assert from 'node:assert/strict'
import type { NextFunction, Request, Response } from 'express'
import { createRateLimitMiddleware, resetRateLimitBucketsForTest } from './rate-limit.js'
test('createRateLimitMiddleware allows requests within the window', () => {
resetRateLimitBucketsForTest()
const limiter = createRateLimitMiddleware({
scope: 'test:allow',
windowMs: 60_000,
max: 2,
})
const req = createMockRequest()
const res = createMockResponse()
let nextCount = 0
const next: NextFunction = () => {
nextCount += 1
}
limiter(req, res, next)
limiter(req, res, next)
assert.equal(nextCount, 2)
assert.equal(res.statusCode, 200)
})
test('createRateLimitMiddleware blocks requests over the limit', () => {
resetRateLimitBucketsForTest()
const limiter = createRateLimitMiddleware({
scope: 'test:block',
windowMs: 60_000,
max: 1,
})
const req = createMockRequest()
const res = createMockResponse()
let nextCount = 0
const next: NextFunction = () => {
nextCount += 1
}
limiter(req, res, next)
limiter(req, res, next)
assert.equal(nextCount, 1)
assert.equal(res.statusCode, 429)
assert.equal(res.headers['Retry-After'], '60')
assert.equal(res.body.errorCode, 'rate_limited')
})
test('createRateLimitMiddleware supports custom limit responses', () => {
resetRateLimitBucketsForTest()
const limiter = createRateLimitMiddleware({
scope: 'test:custom',
windowMs: 60_000,
max: 1,
onLimit: (_req, res) => {
res.status(200).json({ code: 429, message: 'limited' })
},
})
const req = createMockRequest()
const res = createMockResponse()
limiter(req, res, () => {})
limiter(req, res, () => {})
assert.equal(res.statusCode, 200)
assert.deepEqual(res.body, { code: 429, message: 'limited' })
})
function createMockRequest(): Request {
return {
ip: '127.0.0.1',
originalUrl: '/test',
headers: {},
socket: {
remoteAddress: '127.0.0.1',
},
} as Request
}
function createMockResponse(): Response & {
statusCode: number
headers: Record<string, string>
body: any
} {
const res = {
statusCode: 200,
headers: {} as Record<string, string>,
body: null as any,
setHeader(name: string, value: string) {
this.headers[name] = value
return this
},
status(statusCode: number) {
this.statusCode = statusCode
return this
},
json(body: any) {
this.body = body
return this
},
}
return res as Response & {
statusCode: number
headers: Record<string, string>
body: any
}
}