chore: hash rate limit trackers api v2 (#22767)

This commit is contained in:
Morgan
2025-07-30 13:35:12 +03:00
committed by GitHub
parent 96a6350143
commit d1bd05a791
7 changed files with 17 additions and 18 deletions
@@ -5,7 +5,7 @@ import { GetBookingOutput_2024_04_15 } from "@/ee/bookings/2024-04-15/outputs/ge
import { GetBookingsOutput_2024_04_15 } from "@/ee/bookings/2024-04-15/outputs/get-bookings.output";
import { MarkNoShowOutput_2024_04_15 } from "@/ee/bookings/2024-04-15/outputs/mark-no-show.output";
import { PlatformBookingsService } from "@/ee/bookings/shared/platform-bookings.service";
import { hashAPIKey, isApiKey, stripApiKey } from "@/lib/api-key";
import { sha256Hash, isApiKey, stripApiKey } from "@/lib/api-key";
import { VERSION_2024_04_15, VERSION_2024_06_11, VERSION_2024_06_14 } from "@/lib/api-versions";
import { ApiKeysRepository } from "@/modules/api-keys/api-keys-repository";
import { GetUser } from "@/modules/auth/decorators/get-user/get-user.decorator";
@@ -386,7 +386,7 @@ export class BookingsController_2024_04_15 {
if (bearerToken) {
if (isApiKey(bearerToken, this.config.get<string>("api.apiKeyPrefix") ?? "cal_")) {
const strippedApiKey = stripApiKey(bearerToken, this.config.get<string>("api.keyPrefix"));
const apiKeyHash = hashAPIKey(strippedApiKey);
const apiKeyHash = sha256Hash(strippedApiKey);
const keyData = await this.apiKeyRepository.getApiKeyFromHash(apiKeyHash);
return keyData?.userId;
} else {
@@ -11,7 +11,7 @@ import { PlatformBookingsService } from "@/ee/bookings/shared/platform-bookings.
import { EventTypesRepository_2024_06_14 } from "@/ee/event-types/event-types_2024_06_14/event-types.repository";
import { OutputEventTypesService_2024_06_14 } from "@/ee/event-types/event-types_2024_06_14/services/output-event-types.service";
import { apiToInternalintegrationsMapping } from "@/ee/event-types/event-types_2024_06_14/transformers";
import { hashAPIKey, isApiKey, stripApiKey } from "@/lib/api-key";
import { sha256Hash, isApiKey, stripApiKey } from "@/lib/api-key";
import { defaultBookingResponses } from "@/lib/safe-parse/default-responses-booking";
import { safeParse } from "@/lib/safe-parse/safe-parse";
import { ApiKeysRepository } from "@/modules/api-keys/api-keys-repository";
@@ -675,7 +675,7 @@ export class InputBookingsService_2024_08_13 {
if (bearerToken) {
if (isApiKey(bearerToken, this.config.get<string>("api.apiKeyPrefix") ?? "cal_")) {
const strippedApiKey = stripApiKey(bearerToken, this.config.get<string>("api.keyPrefix"));
const apiKeyHash = hashAPIKey(strippedApiKey);
const apiKeyHash = sha256Hash(strippedApiKey);
const keyData = await this.apiKeyRepository.getApiKeyFromHash(apiKeyHash);
return keyData?.userId;
} else {
+1 -1
View File
@@ -1,6 +1,6 @@
import { createHash } from "crypto";
export const hashAPIKey = (apiKey: string): string => createHash("sha256").update(apiKey).digest("hex");
export const sha256Hash = (token: string): string => createHash("sha256").update(token).digest("hex");
export const isApiKey = (authString: string, prefix: string): boolean =>
authString?.startsWith(prefix ?? "cal_");
+5 -6
View File
@@ -1,5 +1,5 @@
import { getEnv } from "@/env";
import { hashAPIKey, isApiKey, stripApiKey } from "@/lib/api-key";
import { sha256Hash, isApiKey, stripApiKey } from "@/lib/api-key";
import { Throttle } from "@/lib/endpoint-throttler-decorator";
import { PrismaReadService } from "@/modules/prisma/prisma-read.service";
import { ThrottlerStorageRedisService } from "@nest-lab/throttler-storage-redis";
@@ -10,7 +10,6 @@ import {
ThrottlerException,
ThrottlerRequest,
ThrottlerModuleOptions,
seconds,
} from "@nestjs/throttler";
import { Request, Response } from "express";
import { z } from "zod";
@@ -218,18 +217,18 @@ export class CustomThrottlerGuard extends ThrottlerGuard {
if (authorizationHeader) {
const apiKeyPrefix = getEnv("API_KEY_PREFIX", "cal_");
return isApiKey(authorizationHeader, apiKeyPrefix)
? `api_key_${hashAPIKey(stripApiKey(authorizationHeader, apiKeyPrefix))}`
: `access_token_${authorizationHeader}`;
? `api_key_${sha256Hash(stripApiKey(authorizationHeader, apiKeyPrefix))}`
: `access_token_${sha256Hash(authorizationHeader)}`;
}
const oauthClientId = request.get(X_CAL_CLIENT_ID);
if (oauthClientId) {
return `oauth_client_${oauthClientId}`;
return `oauth_client_${sha256Hash(oauthClientId)}`;
}
if (IP) {
return `ip_${IP}`;
return `ip_${sha256Hash(IP.toString())}`;
}
this.logger.verbose(`no tracker found: ${request.url}`);
@@ -1,4 +1,4 @@
import { hashAPIKey, stripApiKey } from "@/lib/api-key";
import { sha256Hash, stripApiKey } from "@/lib/api-key";
import { AuthMethods } from "@/lib/enums/auth-methods";
import { ApiKeysRepository } from "@/modules/api-keys/api-keys-repository";
import { CreateApiKeyInput } from "@/modules/api-keys/inputs/create-api-key.input";
@@ -61,7 +61,7 @@ export class ApiKeysService {
async refreshApiKey(authUserId: number, apiKey: string, refreshApiKeyInput: RefreshApiKeyInput) {
const strippedApiKey = stripApiKey(apiKey, this.config.get<string>("api.keyPrefix"));
const apiKeyHash = hashAPIKey(strippedApiKey);
const apiKeyHash = sha256Hash(strippedApiKey);
const apiKeyInDb = await this.apiKeysRepository.getApiKeyFromHash(apiKeyHash);
if (!apiKeyInDb) {
throw new UnauthorizedException("ApiKeysService - provided api key is not valid.");
@@ -1,4 +1,4 @@
import { hashAPIKey, isApiKey, stripApiKey } from "@/lib/api-key";
import { sha256Hash, isApiKey, stripApiKey } from "@/lib/api-key";
import { AuthMethods } from "@/lib/enums/auth-methods";
import { isOriginAllowed } from "@/lib/is-origin-allowed/is-origin-allowed";
import { BaseStrategy } from "@/lib/passport/strategies/types";
@@ -226,7 +226,7 @@ export class ApiAuthStrategy extends PassportStrategy(BaseStrategy, "api-auth")
);
}
const strippedApiKey = stripApiKey(apiKey, this.config.get<string>("api.keyPrefix"));
const apiKeyHash = hashAPIKey(strippedApiKey);
const apiKeyHash = sha256Hash(strippedApiKey);
const keyData = await this.apiKeyRepository.getApiKeyFromHash(apiKeyHash);
if (!keyData) {
throw new UnauthorizedException("ApiAuthStrategy - api key - Your api key is not valid");
@@ -1,7 +1,7 @@
import { bootstrap } from "@/app";
import { AppModule } from "@/app.module";
import { getEnv } from "@/env";
import { hashAPIKey, stripApiKey } from "@/lib/api-key";
import { sha256Hash, stripApiKey } from "@/lib/api-key";
import { RefreshApiKeyOutput } from "@/modules/api-keys/outputs/refresh-api-key.output";
import { CreateOAuthClientResponseDto } from "@/modules/oauth-clients/controllers/oauth-clients/responses/CreateOAuthClientResponse.dto";
import { GetOAuthClientResponseDto } from "@/modules/oauth-clients/controllers/oauth-clients/responses/GetOAuthClientResponse.dto";
@@ -283,7 +283,7 @@ describe("Organizations Organizations Endpoints", () => {
expect(managedOrgApiKeys?.length).toEqual(1);
expect(managedOrgApiKeys?.[0]?.id).toBeDefined();
const apiKeyPrefix = getEnv("API_KEY_PREFIX", "cal_");
const hashedApiKey = `${hashAPIKey(stripApiKey(managedOrg?.apiKey, apiKeyPrefix))}`;
const hashedApiKey = `${sha256Hash(stripApiKey(managedOrg?.apiKey, apiKeyPrefix))}`;
expect(managedOrgApiKeys?.[0]?.hashedKey).toEqual(hashedApiKey);
const expectedExpiresAt = DateTime.fromJSDate(newDate).setZone("utc").plus({ days: 30 }).toJSDate();
expect(managedOrgApiKeys?.[0]?.expiresAt).toEqual(expectedExpiresAt);
@@ -484,7 +484,7 @@ describe("Organizations Organizations Endpoints", () => {
expect(managedOrgApiKeys?.length).toEqual(1);
expect(managedOrgApiKeys?.[0]?.id).toBeDefined();
const apiKeyPrefix = getEnv("API_KEY_PREFIX", "cal_");
const hashedApiKey = `${hashAPIKey(stripApiKey(newApiKey, apiKeyPrefix))}`;
const hashedApiKey = `${sha256Hash(stripApiKey(newApiKey, apiKeyPrefix))}`;
expect(managedOrgApiKeys?.[0]?.hashedKey).toEqual(hashedApiKey);
const expectedExpiresAt = DateTime.fromJSDate(newDate).setZone("utc").plus({ days: 60 }).toJSDate();
expect(managedOrgApiKeys?.[0]?.expiresAt).toEqual(expectedExpiresAt);