Support rate limiting by custom field
italotabatinga opened this issue · comments
Hello there! We've been using this library on our product and it has been working great!
We have another use case, however, that I think might fit in this gem. Instead of rate limiting by IP, we wanted to rate limit by client id.
In our case, this is useful in some sensitive OTP mutations where we want to block brute force attacks per client instead of per IP, considering that an attacker will have a great range of IPs to use.
There's a possible solution below and I'm happy to open a PR if you find this useful too!
suggestion
This solution allows other context keys to be defined as the rate limited key while still keeping IP by default for backward compatibility.
def resolve(object:, arguments:, **_rest)
value = object.context[value]
raise GraphAttack::Error, "Missing #{value} value on the GraphQL context" unless value
return RateLimited.new('Query rate limit exceeded') if calls_exceeded_on_query?(value)
yield(object, arguments)
end
private
def value
options[:value] || :ip
end
In our case, we'd use this like:
extension GraphAttack::RateLimit,
threshold: 60,
interval: 60,
redis_client: REDIS,
value: :customer_uuid,
Hi Ítalo, that sounds like a great addition, I’d be happy to merge something like this! 😍
A few thoughts:
-
Maybe we can find a better name than
value
. To me I find it a bit counter-intuitive that it should hold the key we are using in the context. I’m having a hard time thinking of a better name:rate_limited_key:
,for_context_key:
,field:
,limit_key:
orlimited_by_context_key:
could be ok. Perhaps it could be something even shorter likeon:
. What do you think? -
Since this option is not global but per-field this means we can have several rate limits on one field, for example one per IP and one per customer. For this to work we might need to change the key that is used for rate limiting for it to include the new field. E.g.:
def key on = "-#{options[:on]}" if options[:on] "graphql-query-#{field.name}#{on}" end
I’m having a hard time thinking of a better name:
I was too with rate_limited_key
and field
😆 But I really liked your on
suggestion!
For this to work we might need to change the key that is used for rate limiting for it to include the new field.
Indeed! ty
I think we can follow through with this, sounds good?
Yeah, go for it! 🔥 🔥 \o/