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

[CAL-4413] [Api][v2] implement api key rate limiting #16824

Open
ThyMinimalDev opened this issue Sep 26, 2024 · 0 comments · Fixed by vardhman-shaha/cal.com#1 · May be fixed by #16829
Open

[CAL-4413] [Api][v2] implement api key rate limiting #16824

ThyMinimalDev opened this issue Sep 26, 2024 · 0 comments · Fixed by vardhman-shaha/cal.com#1 · May be fixed by #16829
Labels
api area: API, enterprise API, access token, OAuth ✨ feature New feature or request High priority Created by Linear-GitHub Sync platform Anything related to our platform plan

Comments

@ThyMinimalDev
Copy link
Contributor

ThyMinimalDev commented Sep 26, 2024

override handleRequest in CustomerThrottlerGuard (apps/api/v2/src/lib/throttler-guard.ts) to be able to rate limit based on api key, example:

@Injectable()
export class WsThrottlerGuard extends ThrottlerGuard {
  async handleRequest(requestProps: ThrottlerRequest): Promise<boolean> {
    const { context, limit, ttl, throttler, blockDuration, getTracker, generateKey } = requestProps;

    const client = context.switchToWs().getClient();
    const tracker = client._socket.remoteAddress;
    const key = generateKey(context, tracker, throttler.name);
    const { totalHits, timeToExpire, isBlocked, timeToBlockExpire } =
      await this.storageService.increment(key, ttl, limit, blockDuration, throttler.name);

    const getThrottlerSuffix = (name: string) => (name === 'default' ? '' : `-${name}`);

    // Throw an error when the user reached their limit.
    if (isBlocked) {
      await this.throwThrottlingException(context, {
        limit,
        ttl,
        key,
        tracker,
        totalHits,
        timeToExpire,
        isBlocked,
        timeToBlockExpire,
      });
    }

    return true;
  }
}

new prisma schema RateLimits
id
apiKeyId
ttl
limit
blockDuration

in handleRequest,

  • call this.getTracker to get the rate limiting tracker, if the tracker is for an api key
  • use tracker to check if limit are in cache
  • otherwise get limits from prisma using tracker
  • store limits in cache (1h)
  • increment usage with this.storageService.increment, use default values if nothing in DB
  • if isBlocked, throw error 429
  • else return true

in handleRequest, if tracker is not for an api key

  • use default rate limit values directly with this.storageService.increment
  • if isBlocked, throw error 429
  • else return true
  1. Update throttler
  2. Make schema array multiple rate limits
  3. try to access redis passed
  4. use hashsed key in getTracker
model ApiKey {
  id         String    @id @unique @default(cuid())
  userId     Int
  teamId     Int?
  note       String?
  createdAt  DateTime  @default(now())
  expiresAt  DateTime?
  lastUsedAt DateTime?
  hashedKey  String    @unique()
  user       User?     @relation(fields: [userId], references: [id], onDelete: Cascade)
  team       Team?     @relation(fields: [teamId], references: [id], onDelete: Cascade)
  app        App?      @relation(fields: [appId], references: [slug], onDelete: Cascade)
  appId      String?
  rateLimit  RateLimit?

  @@index([userId])
}

model RateLimit {
  id                 String    @id @default(cuid())
  apiKeyId           String    @unique
  ttl                Int
  limit              Int
  baseBlockDuration  Int   
  maxBlockDuration   Int   
  createdAt          DateTime  @default(now())
  updatedAt          DateTime  @updatedAt

  apiKey             ApiKey    @relation(fields: [apiKeyId], references: [id], onDelete: Cascade)
}

From SyncLinear.com | CAL-4413

@ThyMinimalDev ThyMinimalDev added api area: API, enterprise API, access token, OAuth High priority Created by Linear-GitHub Sync zapier Created by Linear-GitHub Sync labels Sep 26, 2024
@dosubot dosubot bot added the ✨ feature New feature or request label Sep 26, 2024
@ThyMinimalDev ThyMinimalDev added platform Anything related to our platform plan and removed zapier Created by Linear-GitHub Sync labels Sep 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api area: API, enterprise API, access token, OAuth ✨ feature New feature or request High priority Created by Linear-GitHub Sync platform Anything related to our platform plan
Projects
None yet
1 participant