-
Notifications
You must be signed in to change notification settings - Fork 18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Route options #34
base: master
Are you sure you want to change the base?
Route options #34
Conversation
…ay errors and to work with limitd 5.x
@yonjah thanks for the PR. I'm a bit backed up at work but will try to make some time to review |
README.md
Outdated
@@ -44,11 +44,94 @@ The object has the following schema (validated [here](./lib/index.js) using [Joi | |||
* `done: (err: Error, key: String)` - A function that takes an error as the first parameter and the bucket key as the second parameter. | |||
|
|||
**Optional** | |||
* `enabled: Boolean default(true)` - if `true` rate limiting will be enabled you can set it to `false` on route settings to disable rate limiting |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure enabled
is the best way of describing this. e.g.: enabled: false
at the top level can be confusing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"can set it to false
on route settings to disable rate limiting"
Why "on route settings"? If it is done at the global level this is also disabled. What about "if true rate limiting will be enabled. Setting this
false` disable this at the appropriate level (route or global)"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree "enabled" can be confusing but couldn't think of a better term.
I'll change the description as you suggested
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what if we call it allRoutes
and it can only be set at the global plug in level not at the route level? if a route has the plugin defined, it wants to enable it so no need for the flag at the route level
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That sounds good for my use case where I have many routes which are not rate limited and I only want to enable it for a few routes.
But if you want to enable it for most route and only disable it on a few routes it will be more cumbersome
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, I see. let's, leave as is
README.md
Outdated
@@ -44,11 +44,94 @@ The object has the following schema (validated [here](./lib/index.js) using [Joi | |||
* `done: (err: Error, key: String)` - A function that takes an error as the first parameter and the bucket key as the second parameter. | |||
|
|||
**Optional** | |||
* `enabled: Boolean default(true)` - if `true` rate limiting will be enabled you can set it to `false` on route settings to disable rate limiting | |||
* `addHeaders: Boolean default(true)` - if `true` rate limiting headers will be sent with response |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this should be an option. This should always be true. Can you expand on why you think it should be optional?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My main use case for using rate limiting is to disable brute force on login attempts and tokens.
Since I don't see a case where legitimate use will hit those limits and if he does all he need to know is to try again in a few minutes. I don't want to give attacker extra information about when exactly he can do each attempt.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, sounds good. what about sendResponseHeaders
?
README.md
Outdated
@@ -44,11 +44,94 @@ The object has the following schema (validated [here](./lib/index.js) using [Joi | |||
* `done: (err: Error, key: String)` - A function that takes an error as the first parameter and the bucket key as the second parameter. | |||
|
|||
**Optional** | |||
* `enabled: Boolean default(true)` - if `true` rate limiting will be enabled you can set it to `false` on route settings to disable rate limiting | |||
* `addHeaders: Boolean default(true)` - if `true` rate limiting headers will be sent with response | |||
* `count: Number default(1)` - how many tokens request should cost useful when you want one route to be more expensive than another but use the same bucket |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you share a bit more about this use case? I understand the concept, but this is not something that I see being very common
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just thought it might be useful as a route option.
Personally I don't have a use case for it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's drop it for the time being then please. it adds additional logic with no usage
README.md
Outdated
* `onError: (error, reply) => ()` - A function that takes the `error` that occurred when trying to get a token from the bucket and the `reply` interface. | ||
* `error: Error` - The error that occurred. | ||
* `reply: Reply` - The hapi.js [reply interface](http://hapijs.com/api#reply-interface). | ||
> If an error occurs and no function is provided, the request lifecycle continues normally as if there was no token bucket restriction. This is a useful default behavior in case the limitd server goes down. | ||
|
||
Options can be overridden in route settings. | ||
if plugin is disabled by default setting patova setting for route will also enable the plugin for the route. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure about what this particular line means. Can you provide a bit more detail please?
README.md
Outdated
* `onError: (error, reply) => ()` - A function that takes the `error` that occurred when trying to get a token from the bucket and the `reply` interface. | ||
* `error: Error` - The error that occurred. | ||
* `reply: Reply` - The hapi.js [reply interface](http://hapijs.com/api#reply-interface). | ||
> If an error occurs and no function is provided, the request lifecycle continues normally as if there was no token bucket restriction. This is a useful default behavior in case the limitd server goes down. | ||
|
||
Options can be overridden in route settings. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would move from here until "Contributing" to a wiki article, leaving the README.md simpler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you want me to remove this completely or create a wiki page and add a link ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's remove it. it is simple enough
lib/index.js
Outdated
const extractKeyAndTakeToken = function(options, request, reply, type) { | ||
options.extractKey(request, reply, (err, key) =>{ | ||
const limitd = options.limitd; | ||
const count = options.count; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let's discuss usage above, but I would probably remove from now
if (onError) { return onError(err, reply); } | ||
// by default we don't fail if limitd is unavailable | ||
return reply.continue(); | ||
} | ||
|
||
const oldMinimumLimitResponse = request.plugins.patova && request.plugins.patova.limit | ||
const newMinimumLimitResponse = getMinimumLimit(currentLimitResponse, oldMinimumLimitResponse) | ||
const oldMinimumLimitResponse = request.plugins.patova && request.plugins.patova.limit; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks
lib/index.js
Outdated
newMinimumLimitResponse.limit, | ||
newMinimumLimitResponse.remaining, | ||
newMinimumLimitResponse.reset); | ||
if (options.addHeaders) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As mentioned previously, I would not make this optional unless there is a good reason to
lib/index.js
Outdated
reply.continue(); | ||
}); | ||
|
||
function parseRouteOptions(request) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this logic looks good. it is not really parsing though, right? I would change the function name to getRouteOptions
maybe?
lib/index.js
Outdated
} | ||
|
||
exports.register = function (server, options, next) { | ||
Joi.validate(options, schema, { abortEarly: false }, (err, processedOptions) => { | ||
const defaults = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
does it make sense to use Joi default
: https://github.com/hapijs/joi/blob/master/API.md#anydefaultvalue-description?
lib/index.js
Outdated
const extractKeyAndTakeToken = function(options, request, reply, type) { | ||
options.extractKey(request, reply, (err, key) =>{ | ||
const limitd = options.limitd; | ||
const count = options.count; | ||
if (err) { return reply(err); } | ||
|
||
if (!limitd) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW I don't think limitd can be missing or falsey at this stage so this can probably be removed
…rrid route settings
Ok hope it looks better now |
extractKey(request, reply, (err, key) =>{ | ||
const extractKeyAndTakeToken = function(options, request, reply, type) { | ||
options.extractKey(request, reply, (err, key) =>{ | ||
const limitd = options.limitd; | ||
if (err) { return reply(err); } | ||
|
||
if (!limitd) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dschenkelman do you want me to also remove this check ?
I'm not sure why it's there but I don't think limitd
can ever be falsey at this stage
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no, this is fine
lib/index.js
Outdated
if (routeOptions === undefined) { | ||
return pluginOptions; | ||
} | ||
if (routeOptions._merged) { //already merged with previous pluginOptions; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe this is a premature optimization? I think hapi merges per request. Storing _merged
on the plugins.patova
object which we don't own feels odd.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea sure. It just feels a bit wasteful since it can be deduced in advance.
But this is anyway kinda hacky so I don't mind removing it
@@ -44,11 +44,14 @@ The object has the following schema (validated [here](./lib/index.js) using [Joi | |||
* `done: (err: Error, key: String)` - A function that takes an error as the first parameter and the bucket key as the second parameter. | |||
|
|||
**Optional** | |||
* `enabled: Boolean default(true)` - if true rate limiting will be enabled for all routes. Setting this `false` will only rate limit routes which have the plugin defined |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've been thinking a bit more and we can probably change this to allRoutes
as you suggested.
if it's set to true
a user can still disable a specific route by setting the route settings to false
instead of an object
config: {
plugins: {
patova: false
}
}
So we can accommodate both use cases this way.
This pull request will allow to override settings for each route.
I also added a few useful settings to override -
enabled
- to enable rate limiting only for specific routesaddHeaders
- to add rate liming headers to responsecount
- to change the cost of a routeAll new settings are optional and default to original behavior.