Generalized rate-limit package and updated livedata_server.js to accept rules on methods and subscriptions.

Need to add checks and throw errors if wrong format / input to rate-limit package. Updated default rule in ddp-rate-limiter
to reflect new rate-limit generic design and moved the location of the DDPRateLimiter in livedata_server.js. Need to fix tests
for both ddp-rate-limiter and rate-limit packages with updated code and clean up rate-limit package.
This commit is contained in:
Anubhav Jain
2015-06-22 22:38:22 -07:00
parent 3e342e04eb
commit 2fd1c35da1
3 changed files with 45 additions and 34 deletions

View File

@@ -10,7 +10,8 @@ DDPRateLimiter.RateLimiter.addRule( {
IPAddr: function( IPAddr ) {
return true;
},
method: 'login'
type: 'method',
name: 'login'
}, 5, 10000 );
DDPRateLimiter.getErrorMessage = function( rateLimitResult ) {

View File

@@ -545,16 +545,24 @@ _.extend(Session.prototype, {
if (_.has(self.protocol_handlers, msg.msg)) {
// Is it bad to do these checks here? Instead of inside session.protocol_handlers and then in method
// var rateLimiterInput = {
// userId: self.userId,
// IPAddr: self.connectionHandle.clientAddress,
// type: msg.msg,
// name: msg.name }
// DDPRateLimiter.RateLimiter.increment(rateLimiterInput);
// var rateLimitResult = DDPRateLimiter.RateLimiter.check(rateLimiterInput)
// if (!rateLimitResult.valid)
// self.sendError('too-many-requests', DDPRateLimiter.getErrorMessage(rateLimitResult));
// else
var rateLimiterInput = {
userId: self.userId,
IPAddr: self.connectionHandle.clientAddress,
type: msg.msg,
name: null
};
// Janky solution because in method, methodName is in msg.method otherwise in msg.name for subscriptions
if (msg.msg === 'method') {
rateLimiterInput.name = msg.method;
} else if (msg.msg === 'sub') {
rateLimiterInput.name = msg.name;
}
DDPRateLimiter.RateLimiter.newIncrement(rateLimiterInput);
var rateLimitResult = DDPRateLimiter.RateLimiter.newCheck(rateLimiterInput)
if (!rateLimitResult.valid) {
self.sendError('too-many-requests', DDPRateLimiter.getErrorMessage(rateLimitResult));
}
else
self.protocol_handlers[msg.msg].call(self, msg, unblock);
}
else
@@ -658,16 +666,16 @@ _.extend(Session.prototype, {
randomSeed: randomSeed
});
// invocation.method = msg.method;
var rateLimiterInput = {
userId: self.userId,
IPAddr: self.connectionHandle.clientAddress,
method: msg.method};
// var rateLimiterInput = {
// userId: self.userId,
// IPAddr: self.connectionHandle.clientAddress,
// method: msg.method};
try {
DDPRateLimiter.RateLimiter.newIncrement(rateLimiterInput);
var rateLimitResult = DDPRateLimiter.RateLimiter.newCheck(rateLimiterInput)
if (!rateLimitResult.valid) {
throw new Meteor.Error(429, DDPRateLimiter.getErrorMessage(rateLimitResult));
}
// DDPRateLimiter.RateLimiter.newIncrement(rateLimiterInput);
// var rateLimitResult = DDPRateLimiter.RateLimiter.newCheck(rateLimiterInput)
// if (!rateLimitResult.valid) {
// throw new Meteor.Error(429, DDPRateLimiter.getErrorMessage(rateLimitResult));
// }
var result = DDPServer._CurrentWriteFence.withValue(fence, function () {
return DDP._CurrentInvocation.withValue(invocation, function () {

View File

@@ -24,7 +24,7 @@ RateLimiter = function() {
* @return {object} Returns object of whether method invocation is valid, time
* to next reset and number invocations left
*/
RateLimiter.prototype.check = function( methodInvocation ) {
/*RateLimiter.prototype.check = function( methodInvocation ) {
var self = this;
var reply = {
valid: true,
@@ -63,7 +63,7 @@ RateLimiter.prototype.check = function( methodInvocation ) {
} );
return reply;
}
} */
RateLimiter.prototype.newCheck = function ( input ) {
var self = this;
@@ -124,7 +124,7 @@ RateLimiter.prototype.addRule = function( rule, numRequestsAllowed,
* added 'method' attribute listing the method name
* @return {boolean} Returns whether the methodInvocation matches inputted rule
*/
RateLimiter.prototype.matchRuleUsingFind = function( rule, methodInvocation ) {
/*RateLimiter.prototype.matchRuleUsingFind = function( rule, methodInvocation ) {
var self = this;
var ruleMatches = true;
_.find( RATE_LIMITING_DICT, function( value, key ) {
@@ -146,7 +146,7 @@ RateLimiter.prototype.matchRuleUsingFind = function( rule, methodInvocation ) {
} );
return ruleMatches;
}
}*/
RateLimiter.prototype._matchRule = function ( rule, input ) {
var self = this;
@@ -180,7 +180,7 @@ RateLimiter.prototype._matchRule = function ( rule, input ) {
* @param {object} methodInvocation DDPCommon.MethodInvocation object with
* added 'method' attribute listing the method name
*/
RateLimiter.prototype.increment = function( methodInvocation ) {
/*RateLimiter.prototype.increment = function( methodInvocation ) {
var self = this;
// Figure out all the rules this method invocation matches
_.each( this.rules, function( rule ) {
@@ -212,7 +212,7 @@ RateLimiter.prototype.increment = function( methodInvocation ) {
}
}
} );
}
}*/
RateLimiter.prototype.newIncrement = function ( input ) {
var self = this;
@@ -258,7 +258,7 @@ RateLimiter.prototype._createNewRuleId = function() {
* @return {string} Key string made of all fields from rule that match in
* method invocation
*/
RateLimiter.prototype._generateMethodInvocationKeyStringFromRuleMapping =
/*RateLimiter.prototype._generateMethodInvocationKeyStringFromRuleMapping =
function( rule, methodInvocation ) {
var self = this;
var returnString = "";
@@ -275,7 +275,7 @@ RateLimiter.prototype._generateMethodInvocationKeyStringFromRuleMapping =
}
} );
return returnString;
}
}*/
RateLimiter.prototype._generateKeyString = function (rule, input) {
var self = this;
@@ -283,11 +283,13 @@ RateLimiter.prototype._generateKeyString = function (rule, input) {
_.each( rule, function ( value, key) {
if (value !== null) {
if (typeof value === 'function') {
if (value(input[key]))
if (value(input[key])){
returnString += key + input[key];
}
}
else
else{
returnString += key + input[key];
}
}
});
return returnString;
@@ -302,7 +304,7 @@ RateLimiter.prototype._generateKeyString = function (rule, input) {
* @return {object} Returns a string, value, or object of whatever is stored in
* appropriate field in MethodInvocation
*/
RateLimiter.prototype._ruleMappingtoMethodInvocationDict = function( key,
/*RateLimiter.prototype._ruleMappingtoMethodInvocationDict = function( key,
methodInvocation ) {
var arr = RATE_LIMITING_DICT[ key ].split( '.' );
@@ -311,8 +313,8 @@ RateLimiter.prototype._ruleMappingtoMethodInvocationDict = function( key,
methodInvocation = methodInvocation[ firstGuy ];
}
return methodInvocation;
};
}; */
/*
RateLimiter.prototype._matchRuleHelper = function( rule, methodInvocation ) {
var self = this;
@@ -325,7 +327,7 @@ RateLimiter.prototype._matchRuleHelper = function( rule, methodInvocation ) {
timeSinceLastReset: timeSinceLastReset,
timeToNextReset: timeToNextReset
};
}
} */
RateLimiter.prototype._newRuleHelper = function (rule, input) {
var self = this;