diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8d566c0 --- /dev/null +++ b/Makefile @@ -0,0 +1,4 @@ +.PHONY: test + +test: + ./node_modules/.bin/mocha tests diff --git a/README.md b/README.md index a1c8176..8399e3c 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,16 @@ -rate-limitter -============= +## Express rate-limitter +Rate limiting middleware for Express applications. -Rate limiting middleware for Express + +``` js +var limitter = require('expa').limitter(app, client) + +limitter({ + path: '/like', + method: 'get', + lookup: ['req.user.id', 'req.connection.remoteAddress'], + total: 100, + expire: 1000 * 60 * 60 +}) + +``` diff --git a/index.js b/index.js new file mode 100644 index 0000000..c8c461a --- /dev/null +++ b/index.js @@ -0,0 +1,39 @@ +module.exports = function (app, db) { + return function (opts) { + app[opts.method](opts.path, function (req, res, next) { + opts.lookup = Array.isArray(opts.lookup) ? opts.lookup : [opts.lookup] + var lookups = opts.lookup.map(function (item) { + return item + item.split('.').reduce(function (prev, cur) { + return prev[cur] + }, req) + }).join(':') + + var key = 'ratelimit:' + path + ':' + method + ':' + lookups + db.get(key, function (err, limit) { + var now = Date.now() + limit = limit ? JSON.parse(limit) : { + total: total, + remaining: total, + reset: now + opts.expire + } + + if (now > limit.reset) limit.reset = now + opts.expire + + limit.remaining = Number(limit.remaining) - 1 + + db.set(key, JSON.stringify(limit) + + res.set('X-RateLimit-Limit', limit.total) + res.set('X-RateLimit-Remaining', limit.remaining) + + if (limit.remaining) return next() + + var after = (limit.reset - Date.now()) / 1000 + + res.set('Retry-After', after) + res.send(429, 'Rate limit exceeded') + }) + + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..f75a7dc --- /dev/null +++ b/package.json @@ -0,0 +1,22 @@ +{ + "name": "rate-limitter", + "version": "0.0.0", + "description": "rate limitter middleware for express applications", + "main": "index.js", + "author": "Dustin Diaz", + "license": "MIT", + "scripts": { + "test": "make test" + }, + "repository": { + "type": "git", + "url": "git://github.com/ded/rate-limitter.git" + }, + "bugs": { + "url": "https://github.com/ded/rate-limitter/issues" + }, + "homepage": "https://github.com/ded/rate-limitter", + "devDependencies": { + "mocha": "~1.18.2" + } +}