Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

fastify-rate-limit

Package Overview
Dependencies
Maintainers
8
Versions
36
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

fastify-rate-limit - npm Package Compare versions

Comparing version 3.0.1 to 4.0.0

.dependabot/config.yml

4

example/example-custom.js

@@ -74,5 +74,5 @@ 'use strict'

KnexStore.prototype.child = function (routeOptions) {
const options = Object.assign(this.options, routeOptions.config.rateLimit)
const options = Object.assign(this.options, routeOptions)
const store = new KnexStore(options)
store.routeKey(routeOptions.method + routeOptions.url)
store.routeKey(routeOptions.routeInfo.method + routeOptions.routeInfo.url)
return store

@@ -79,0 +79,0 @@ }

'use strict'
const Redis = require('ioredis')
const redis = new Redis()
const redis = new Redis({
connectionName: 'my-connection-name',
host: 'localhost',
port: 6379,
connectTimeout: 500,
maxRetriesPerRequest: 1
})

@@ -6,0 +12,0 @@ const fastify = require('fastify')()

/// <reference types="node" />
import * as fastify from 'fastify';
import * as https from "https";
import { Server, IncomingMessage, ServerResponse } from "http";
import { Http2SecureServer, Http2Server, Http2ServerRequest, Http2ServerResponse } from "http2";
import { FastifyPlugin, FastifyRequest, RouteOptions, RawServerBase, RawServerDefault, RawRequestDefaultExpression, RequestGenericInterface } from 'fastify';
type HttpServer = Server | Http2Server | Http2SecureServer | https.Server;
type HttpRequest = IncomingMessage | Http2ServerRequest;
type HttpResponse = ServerResponse | Http2ServerResponse;
declare module "fastify" {
interface FastifyReply<HttpResponse> {}
declare module 'fastify' {
interface FastifyRequestInterface<
RawServer extends RawServerBase = RawServerDefault,
RawRequest extends RawRequestDefaultExpression<RawServer> = RawRequestDefaultExpression<RawServer>,
RequestGeneric extends RequestGenericInterface = RequestGenericInterface
> {
ip: string | number
}
}
declare function fastifyRateLimit(): fastify.Plugin<
Server,
IncomingMessage,
ServerResponse,
{
global?: boolean;
max?: number | ((req: fastify.FastifyRequest<IncomingMessage>, key: string) => number);
timeWindow?: number;
cache?: number;
store?: fastifyRateLimit.FastifyRateLimitStoreCtor;
whitelist?: string[] | ((req: fastify.FastifyRequest<IncomingMessage>, key: string) => boolean);
redis?: any;
skipOnError?: boolean;
ban?: number;
keyGenerator?: (req: fastify.FastifyRequest<IncomingMessage>) => string | number;
errorResponseBuilder?: (req: fastify.FastifyRequest<IncomingMessage>, context: fastifyRateLimit.errorResponseBuilderContext) => object;
addHeaders?: fastifyRateLimit.AddHeaders;
}
>;
export interface FastifyRateLimitOptions {}
declare namespace fastifyRateLimit {
interface FastifyRateLimitOptions {}
export interface errorResponseBuilderContext {
after: string;
max: number;
}
interface errorResponseBuilderContext {
after: string;
max: number;
}
export interface FastifyRateLimitStoreCtor {
new (options: FastifyRateLimitOptions): FastifyRateLimitStore;
}
interface FastifyRateLimitStoreCtor {
new (options: FastifyRateLimitOptions): FastifyRateLimitStore;
}
export interface FastifyRateLimitStore {
incr(key: string, callback: ( error: Error|null, result?: { current: number, ttl: number } ) => void): void;
child(routeOptions: RouteOptions & { path: string, prefix: string }): FastifyRateLimitStore;
}
interface FastifyRateLimitStore {
incr(key: string, callback: ( error: Error|null, result?: { current: number, ttl: number } ) => void): void;
child(routeOptions: fastify.RouteOptions<Server, IncomingMessage, ServerResponse> & { path: string, prefix: string }): FastifyRateLimitStore;
}
interface AddHeaders {
'x-ratelimit-limit'?: boolean,
'x-ratelimit-remaining'?: boolean,
'x-ratelimit-reset'?: boolean,
'retry-after'?: boolean
}
interface AddHeaders {
'x-ratelimit-limit'?: boolean,
'x-ratelimit-remaining'?: boolean,
'x-ratelimit-reset'?: boolean,
'retry-after'?: boolean
}
export interface RateLimitPluginOptions {
global?: boolean;
max?: number | ((req: FastifyRequest, key: string) => number);
timeWindow?: number;
cache?: number;
store?: FastifyRateLimitStoreCtor;
whitelist?: string[] | ((req: FastifyRequest, key: string) => boolean);
redis?: any;
skipOnError?: boolean;
ban?: number;
keyGenerator?: (req: FastifyRequest) => string | number;
errorResponseBuilder?: (req: FastifyRequest, context: errorResponseBuilderContext) => object;
addHeaders?: AddHeaders;
}
export = fastifyRateLimit;
declare const fastifyRateLimit: FastifyPlugin<RateLimitPluginOptions>;
export default fastifyRateLimit;

@@ -66,3 +66,3 @@ 'use strict'

? settings.keyGenerator
: (req) => req.raw.ip
: (req) => req.ip

@@ -84,7 +84,4 @@ globalParams.errorResponseBuilder = (req, context) => ({ statusCode: context.statusCode, error: 'Too Many Requests', message: `Rate limit exceeded, retry in ${context.after}` })

const mergedRateLimitParams = makeParams(routeOptions.config.rateLimit)
if (!routeOptions.config.rateLimit.timeWindow) {
// load the global timewindow if it is missing from the route config
routeOptions.config.rateLimit.timeWindow = mergedRateLimitParams.timeWindow
}
current.store = pluginComponent.store.child(routeOptions)
mergedRateLimitParams.routeInfo = routeOptions
current.store = pluginComponent.store.child(mergedRateLimitParams)
// if the current endpoint have a custom rateLimit configuration ...

@@ -91,0 +88,0 @@ buildRouteRate(current, mergedRateLimitParams, routeOptions)

{
"name": "fastify-rate-limit",
"version": "3.0.1",
"version": "4.0.0",
"description": "A low overhead rate limiter for your routes",

@@ -9,3 +9,3 @@ "main": "index.js",

"test": "standard && tap --cov test/*.test.js && npm run typescript",
"typescript": "tsc --project ./test/types/tsconfig.json"
"typescript": "tsd"
},

@@ -28,23 +28,21 @@ "repository": {

"devDependencies": {
"@types/ioredis": "~4.0.11",
"@types/node": "~12.11.0",
"fastify": "^2.5.0",
"@types/ioredis": "~4.16.0",
"@types/node": "~13.13.4",
"fastify": "^3.0.0-rc.1",
"ioredis": "^4.9.0",
"knex": "^0.20.2",
"knex": "^0.21.1",
"sqlite3": "^4.1.0",
"standard": "^14.0.2",
"tap": "^12.6.6",
"typescript": "^3.4.2"
"tap": "^14.10.7",
"tsd": "^0.11.0"
},
"dependencies": {
"fast-json-stringify": "^1.14.0",
"fastify-plugin": "^1.3.0",
"fast-json-stringify": "^2.0.0",
"fastify-plugin": "^2.0.0",
"ms": "^2.1.1",
"tiny-lru": "^7.0.0"
},
"greenkeeper": {
"ignore": [
"tap"
]
"tsd": {
"directory": "test/types"
}
}
# fastify-rate-limit
[![Greenkeeper badge](https://badges.greenkeeper.io/fastify/fastify-rate-limit.svg)](https://greenkeeper.io/)
[![js-standard-style](https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat)](http://standardjs.com/)
[![Build Status](https://travis-ci.org/fastify/fastify-rate-limit.svg?branch=master)](https://travis-ci.org/fastify/fastify-rate-limit)
![CI workflow](https://github.com/fastify/fastify-rate-limit/workflows/CI%20workflow/badge.svg)

@@ -87,3 +86,3 @@ A low overhead rate limiter for your routes. Supports Fastify `2.x` versions.

- `redis`: by default this plugins uses an in-memory store, which is fast but if you application works on more than one server it is useless, since the data is store locally.<br>
You can pass a Redis client here and magically the issue is solved. To achieve the maximum speed, this plugins requires the use of [`ioredis`](https://github.com/luin/ioredis)
You can pass a Redis client here and magically the issue is solved. To achieve the maximum speed, this plugins requires the use of [`ioredis`](https://github.com/luin/ioredis). **Note:**: the [default parameters](https://github.com/luin/ioredis/blob/v4.16.0/API.md#new_Redis_new) of a redis connection are not the fastest to provide a rate-limit. We suggest to customize the `connectTimeout` and `maxRetriesPerRequest` as in the [`example`](https://github.com/fastify/fastify-rate-limit/tree/master/example/example.js).
- `store`: a custom store to track requests and rates which allows you to use your own storage mechanism (such as using an RDBMS, MongoDB, etc...) as well as further customizing the logic used in calculating the rate limits. A simple example is provided below as well as a more detailed example using Knex.js can be found in the [`example/`](https://github.com/fastify/fastify-rate-limit/tree/master/example) folder

@@ -145,2 +144,5 @@ - `skipOnError`: if `true` it will skip errors generated by the storage (eg, redis not reachable).

Custom `store` example usage:
NOTE: The ```timeWindow``` will always be passed as the numeric value in millseconds into the store's constructor.
```js

@@ -161,3 +163,3 @@ function CustomStore (options) {

// route parameters and pass them into the child store.
const childParams = Object.assign(this.options, routeOptions.config.rateLimit)
const childParams = Object.assign(this.options, routeOptions)
const store = new CustomStore(childParams)

@@ -176,2 +178,6 @@ // Here is where you may want to do some custom calls on the store with the information

The `routeOptions` object passed to the the `child` method of the store will contain the same options that are detailed above for plugin registration with any specific overrides provided on the route. In addition the following parameter is provided:
- `routeInfo`: The configuration of the route including `method`, `url`, `path`, and the full route `config`
### Options on the endpoint itself

@@ -178,0 +184,0 @@

@@ -35,6 +35,6 @@ 'use strict'

LocalStore.prototype.child = function (routeOptions) {
return new LocalStore(routeOptions.config.rateLimit.timeWindow,
routeOptions.config.rateLimit.cache, this.app)
return new LocalStore(routeOptions.timeWindow,
routeOptions.cache, this.app)
}
module.exports = LocalStore

@@ -33,4 +33,4 @@ 'use strict'

const child = Object.create(this)
child.key = this.key + routeOptions.method + routeOptions.url + '-'
child.timeWindow = routeOptions.config.rateLimit.timeWindow
child.key = this.key + routeOptions.routeInfo.method + routeOptions.routeInfo.url + '-'
child.timeWindow = routeOptions.timeWindow
return child

@@ -37,0 +37,0 @@ }

@@ -783,2 +783,54 @@ 'use strict'

test('timeWindow specified as a string', t => {
t.plan(12)
function CustomStore (options) {
this.options = options
this.current = 0
}
CustomStore.prototype.incr = function (key, cb) {
const timeWindow = this.options.timeWindow
this.current++
cb(null, { current: this.current, ttl: timeWindow - (this.current * 1000) })
}
CustomStore.prototype.child = function (routeOptions) {
const store = new CustomStore(Object.assign(this.options, routeOptions))
return store
}
const fastify = Fastify()
fastify.register(rateLimit, {
global: false,
store: CustomStore
})
fastify.get('/', {
config: { rateLimit: { max: 2, timeWindow: '10 seconds' } }
}, (req, reply) => {
reply.send('hello!')
})
fastify.inject('/', (err, res) => {
t.error(err)
t.strictEqual(res.statusCode, 200)
t.strictEqual(res.headers['x-ratelimit-limit'], 2)
t.strictEqual(res.headers['x-ratelimit-remaining'], 1)
t.strictEqual(res.headers['x-ratelimit-reset'], 9)
fastify.inject('/', (err, res) => {
t.error(err)
t.strictEqual(res.statusCode, 200)
t.strictEqual(res.headers['x-ratelimit-limit'], 2)
t.strictEqual(res.headers['x-ratelimit-remaining'], 0)
t.strictEqual(res.headers['x-ratelimit-reset'], 8)
fastify.inject('/', (err, res) => {
t.error(err)
t.strictEqual(res.statusCode, 429)
})
})
})
})
test('With CustomStore', t => {

@@ -798,3 +850,3 @@ t.plan(18)

CustomStore.prototype.child = function (routeOptions) {
const store = new CustomStore(Object.assign(this.options, routeOptions.config.rateLimit))
const store = new CustomStore(Object.assign(this.options, routeOptions))
return store

@@ -801,0 +853,0 @@ }

import * as http from 'http'
import * as http2 from 'http2'
import * as fastify from 'fastify';
import * as types from '../../index';
import * as fastifyRateLimit from '../../../fastify-rate-limit';
import fastify, { RouteOptions, FastifyRequest, FastifyInstance } from 'fastify';
import * as ioredis from 'ioredis';
import fastifyRateLimit, { FastifyRateLimitStore, FastifyRateLimitOptions, errorResponseBuilderContext, RateLimitPluginOptions } from '../../';
class CustomStore implements types.FastifyRateLimitStore {
constructor(options: types.FastifyRateLimitOptions) {}
class CustomStore implements FastifyRateLimitStore {
constructor(options: FastifyRateLimitOptions) {}
incr(key: string, callback: ( error: Error|null, result?: { current: number, ttl: number } ) => void) {}
child(routeOptions: fastify.RouteOptions<http.Server, http.IncomingMessage, http.ServerResponse> & { path: string, prefix: string }) {
return <CustomStore>(<types.FastifyRateLimitOptions>{})
child(routeOptions: RouteOptions & { path: string, prefix: string }) {
return <CustomStore>(<FastifyRateLimitOptions>{})
}

@@ -17,3 +16,3 @@ }

const appWithImplicitHttp = fastify()
const options1 = {
const options1: RateLimitPluginOptions = {
global: true,

@@ -27,4 +26,4 @@ max: 3,

ban: 10,
keyGenerator: (req: fastify.FastifyRequest<http.IncomingMessage>) => req.ip,
errorResponseBuilder: (req: fastify.FastifyRequest<http.IncomingMessage>, context: fastifyRateLimit.errorResponseBuilderContext) => ({ code: 429, timeWindow: context.after, limit: context.max }),
keyGenerator: (req: FastifyRequest<http.Server, http.IncomingMessage>) => req.ip,
errorResponseBuilder: (req: FastifyRequest<http.Server, http.IncomingMessage>, context: errorResponseBuilderContext) => ({ code: 429, timeWindow: context.after, limit: context.max }),
addHeaders: {

@@ -40,4 +39,4 @@ 'x-ratelimit-limit': false,

global: true,
max: (req: fastify.FastifyRequest<http.IncomingMessage>, key: string) => (42),
whitelist: (req: fastify.FastifyRequest<http.IncomingMessage>, key: string) => (false),
max: (req: FastifyRequest<http.Server, http.IncomingMessage>, key: string) => (42),
whitelist: (req: FastifyRequest<http.Server, http.IncomingMessage>, key: string) => (false),
timeWindow: 5000

@@ -48,3 +47,3 @@ }

global: true,
max: (req: fastify.FastifyRequest<http.IncomingMessage>, key: string) => (42),
max: (req: FastifyRequest<http.Server, http.IncomingMessage>, key: string) => (42),
timeWindow: 5000,

@@ -58,3 +57,3 @@ store: CustomStore

const appWithHttp2: fastify.FastifyInstance<
const appWithHttp2: FastifyInstance<
http2.Http2Server,

@@ -61,0 +60,0 @@ http2.Http2ServerRequest,

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc