-
Notifications
You must be signed in to change notification settings - Fork 15
/
index.js
123 lines (102 loc) · 2.54 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
var clients = {},
whitelist,
blacklist,
end = false,
config = {
whitelist: {
totalRequests: -1,
every: 60 * 60 * 1000
},
blacklist: {
totalRequests: 0,
every: 60 * 60 * 1000
},
normal: {
totalRequests: 500,
every: 60 * 60 * 1000
}
};
module.exports = function (options) {
var categories;
if (!options){
options = {};
}
whitelist = options.whitelist || [];
blacklist = options.blacklist || [];
end = options.end || end;
categories = options.categories || options.catagories;
if (categories){
deepExtend(config, categories);
}
return middleware;
};
function middleware (req, res, next) {
var name = req.headers['x-forwarded-for'] || req.connection.remoteAddress,
type = getClientType(name),
client = clients[name];
res.ratelimit = {
clients: clients,
exceeded: false
};
if (req.url === '/favicon.ico') {
next();
return;
};
if (!client) {
clients[name] = client = new Client(name, type, config[type].every);
}
res.setHeader('X-RateLimit-Limit', config[type].totalRequests);
res.setHeader('X-RateLimit-Remaining', config[type].totalRequests - client.visits);
res.ratelimit.exceeded = !ok(client);
res.ratelimit.client = client;
if (ok(client)) {
client.visits++;
next();
}
else if (end === false) {
next();
}
else {
res.setHeader('Content-Type', 'application/json');
res.statusCode = 429;
res.end('{"error":"Rate limit exceded."}');
}
}
function Client (name, type, resetIn) {
var name = name;
this.name = name;
this.type = type;
this.visits = 1;
setTimeout(function () {
delete clients[name];
}, resetIn);
}
function ok (client) {
if (config[client.type].totalRequests === -1) {
return true;
} else {
return client.visits <= config[client.type].totalRequests;
}
}
function getClientType (name) {
if (whitelist.indexOf(name) > -1) {
return 'whitelist';
}
if (blacklist.indexOf(name) > -1) {
return 'blacklist';
}
return 'normal';
}
function deepExtend (destination, source) {
var property;
for (property in source) {
if (source[property] && source[property].constructor &&
source[property].constructor === Object) {
destination[property] = destination[property] || {};
deepExtend(destination[property], source[property]);
} else {
destination[property] = source[property];
}
}
return destination;
}