Skip to content
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

Add Deny List Feature & Add Reasons to limit Response #109

Merged
merged 15 commits into from
Jun 3, 2024
Merged

Conversation

CahidArda
Copy link
Contributor

@CahidArda CahidArda commented May 30, 2024

Deny List

In redis, we keep sets of denied values. One set each for identifiers, ips, countries and user agents. Finally, there is a set of all blocked values. Upstash console is responsible for managing these sets. Ratelimit sdk is only interested in the set of all blocked values stored in key <prefix>:denyList:all.

Enabling deny list in the sdk:

const ratelimit = new Ratelimit({
  redis: Redis.fromEnv(),
  limiter: Ratelimit.slidingWindow(10, "10 s"),
  enableProtection: true // set to true
});

Passing ip, user agent or country in limit:

ratelimit.limit(
  "identifier",
  {
    ip: "12.32.12.32",
    userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X x.y; rv:42.0) Gecko/20100101 Firefox/42.0",
    country: "Germany"
  }
)

all three fields are optional. One can pass none/some/all.

Inside limit, we check if any of the three fields or the identifier is in the deny list. If so, we return {success: false, reason: "denyList", ...}

Deny List Cache

When a value is found in the deny list at redis, we store the value for a minute in a local cache. If that value is passed to the limit method in the next minute, we block the request with reason: "denyList" without making any requests to Redis.

reason field in limit response

We add a new field to the response of limit, which can be either "timeout", "cacheBlock" or "denyList". In the case of "denyList", there is an additional field _deniedValue which denotes the value in deny list.

Deny List Analytics

When a request is denied, we submit increment {identifier: <deniedValue>, success:"denied"} by one.

Previously:

  • the identifier could only be the identifier value passed to limit. Now it can be one of the 4 parameters.
  • success could only be true or false. Now we allow "denied" to count the denied responses.

Todo:

Copy link

linear bot commented May 30, 2024

Copy link

vercel bot commented May 30, 2024

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
ratelimit-with-vercel-kv ✅ Ready (Inspect) Visit Preview 💬 Add feedback May 31, 2024 10:14am

src/analytics.ts Outdated Show resolved Hide resolved
src/denyList.ts Outdated Show resolved Hide resolved
src/denyList.ts Outdated Show resolved Hide resolved
src/denyList.ts Outdated Show resolved Hide resolved
src/types.ts Outdated Show resolved Hide resolved
src/types.ts Outdated Show resolved Hide resolved
src/analytics.ts Show resolved Hide resolved
src/ratelimit.ts Outdated Show resolved Hide resolved
src/ratelimit.ts Outdated Show resolved Hide resolved
ogzhanolguncu
ogzhanolguncu previously approved these changes May 31, 2024
@CahidArda
Copy link
Contributor Author

I think we can go ahead with this PR even though the tests are not passing because they are flaky. Here are two runs with two different tests failing even though the code didn't change between them: 1, 2.

I looked into recording network traffic like langchain does but that's only in python. I want to fix the tests but let's do it another time

@ogzhanolguncu ogzhanolguncu merged commit 7e5e9e1 into main Jun 3, 2024
2 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants