diff --git a/core/api/src/app/authentication/totp.ts b/core/api/src/app/authentication/totp.ts index 10ac79acbb..39206ecf15 100644 --- a/core/api/src/app/authentication/totp.ts +++ b/core/api/src/app/authentication/totp.ts @@ -1,17 +1,21 @@ +import { createHash } from "crypto" + +import { checkLoginAttemptPerLoginIdentifierLimits } from "./ratelimits" + import { AuthTokenUserIdMismatchError, IdentifierNotFoundError, } from "@/domain/authentication/errors" import { - validateKratosToken, - kratosValidateTotp, - kratosInitiateTotp, + AuthWithEmailPasswordlessService, + AuthWithPhonePasswordlessService, kratosElevatingSessionWithTotp, + kratosInitiateTotp, kratosRemoveTotp, + kratosValidateTotp, logoutSessionByAuthToken, refreshToken, - AuthWithPhonePasswordlessService, - AuthWithEmailPasswordlessService, + validateKratosToken, } from "@/services/kratos" import { kratosAdmin } from "@/services/kratos/private" @@ -119,6 +123,17 @@ export const elevatingSessionWithTotp = async ({ authToken: AuthToken totpCode: TotpCode }): Promise => { + // hashing the authToken to use it as a key for the rate limit + // this limit exposure of the authToken in redis + const hashedAuthToken = createHash("sha256") + .update(authToken) + .digest("hex") as HashedAuthToken + + { + const limitOk = await checkLoginAttemptPerLoginIdentifierLimits(hashedAuthToken) + if (limitOk instanceof Error) return limitOk + } + return kratosElevatingSessionWithTotp({ authToken, totpCode }) } diff --git a/core/api/src/domain/authentication/index.types.d.ts b/core/api/src/domain/authentication/index.types.d.ts index e40fcc3fa1..4c553d297b 100644 --- a/core/api/src/domain/authentication/index.types.d.ts +++ b/core/api/src/domain/authentication/index.types.d.ts @@ -10,6 +10,9 @@ type UserId = string & { readonly brand: unique symbol } type PrivilegedClientId = string & { readonly brand: unique symbol } type AuthToken = string & { readonly brand: unique symbol } +// when used in redis for rate limiting +type HashedAuthToken = string & { readonly brand: unique symbol } + type TotpSecret = string & { readonly brand: unique symbol } type TotpCode = string & { readonly brand: unique symbol } diff --git a/core/api/src/domain/users/index.types.d.ts b/core/api/src/domain/users/index.types.d.ts index 289a95c01e..83c3dd1de3 100644 --- a/core/api/src/domain/users/index.types.d.ts +++ b/core/api/src/domain/users/index.types.d.ts @@ -4,7 +4,7 @@ type PhoneCode = string & { readonly brand: unique symbol } type EmailAddress = string & { readonly brand: unique symbol } type EmailCode = string & { readonly brand: unique symbol } -type LoginIdentifier = PhoneNumber | EmailAddress +type LoginIdentifier = PhoneNumber | EmailAddress | HashedAuthToken type DeviceId = string & { readonly brand: unique symbol }