mirror of
https://github.com/andwati/zitadel.git
synced 2026-10-18 05:52:51 +00:00
# Which Problems Are Solved TOTP codes could be reused, violating [RFC 6238, section 5.2](https://datatracker.ietf.org/doc/html/rfc6238#section-5.2). # How the Problems Are Solved Transmitted codes are now recorded in each success event. As the codes amount to secrets, they are not stored verbatim but as a randomly salted HMAC-SHA256 (`crypto.HMACValue`). Each value gets a fresh random salt, so an equal code always produces a different stored value and two entries can never be recognized as being derived from the same code. This is deliberately not a replacement for proper secret storage: with the salt stored alongside the hash and a 6 digit payload, anyone with event access can brute-force the code in milliseconds. That is acceptable here because a code is worthless once its window has passed. The `HMACValue` doc comment states the same. TOTP codes are low-entropy (6 digits), pseudo random codes. Therefore it is possible for the same code to be generated more than once over the lifetime of a user. In order to prevent the (unlikely) case where users login with large time intervalls and a generated code may be equal to the one last used a long time ago, we only check for codes used within the recent period window. A simpler implementation would be simply storing the latest consumed step, but the TOTP library does not return this value. Because of the allowed skew there are always 3 steps within the validation window, so we can't calculate the current step based on time alone. The retained history spans one period more than the validation window: validity is decided by the app server's clock, while the stored events carry the database clock, and the extra period absorbs the drift between them. **Note:** a reused code pushes a distinct `user.human.mfa.otp.check.reused` event, not a failed check event. A replay therefore stays observable through the Events API without counting towards the lockout policy. Otherwise anyone who captured a code could replay it to lock the user out. # Additional Changes - Read only the latest events in recheck query # Additional Context - Closes https://github.com/zitadel/zitadel/issues/6452 --------- Co-authored-by: Livio Spring <[email protected]> Co-authored-by: Copilot Autofix powered by AI <[email protected]> Co-authored-by: copilot-swe-agent[bot] <[email protected]> Co-authored-by: muhlemmer <[email protected]>
147 lines
16 KiB
Go
147 lines
16 KiB
Go
package user
|
|
|
|
import (
|
|
"github.com/zitadel/zitadel/internal/eventstore"
|
|
)
|
|
|
|
func init() {
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserV1AddedType, HumanAddedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserV1RegisteredType, HumanRegisteredEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserV1InitialCodeAddedType, HumanInitialCodeAddedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserV1InitialCodeSentType, HumanInitialCodeSentEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserV1InitializedCheckSucceededType, HumanInitializedCheckSucceededEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserV1InitializedCheckFailedType, HumanInitializedCheckFailedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserV1SignedOutType, HumanSignedOutEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserV1PasswordChangedType, HumanPasswordChangedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserV1PasswordCodeAddedType, HumanPasswordCodeAddedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserV1PasswordCodeSentType, eventstore.GenericEventMapper[HumanPasswordCodeSentEvent])
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserV1PasswordCheckSucceededType, HumanPasswordCheckSucceededEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserV1PasswordCheckFailedType, HumanPasswordCheckFailedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserV1EmailChangedType, HumanEmailChangedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserV1EmailVerifiedType, HumanEmailVerifiedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserV1EmailVerificationFailedType, HumanEmailVerificationFailedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserV1EmailCodeAddedType, HumanEmailCodeAddedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserV1EmailCodeSentType, HumanEmailCodeSentEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserV1PhoneChangedType, HumanPhoneChangedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserV1PhoneRemovedType, HumanPhoneRemovedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserV1PhoneVerifiedType, HumanPhoneVerifiedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserV1PhoneVerificationFailedType, HumanPhoneVerificationFailedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserV1PhoneCodeAddedType, HumanPhoneCodeAddedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserV1PhoneCodeSentType, eventstore.GenericEventMapper[HumanPhoneCodeSentEvent])
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserV1ProfileChangedType, HumanProfileChangedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserV1AddressChangedType, HumanAddressChangedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserV1MFAInitSkippedType, HumanMFAInitSkippedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserV1MFAOTPAddedType, HumanOTPAddedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserV1MFAOTPVerifiedType, HumanOTPVerifiedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserV1MFAOTPRemovedType, HumanOTPRemovedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserV1MFAOTPCheckSucceededType, HumanOTPCheckSucceededEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserV1MFAOTPCheckFailedType, HumanOTPCheckFailedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserLockedType, UserLockedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserUnlockedType, UserUnlockedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserDeactivatedType, UserDeactivatedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserReactivatedType, UserReactivatedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserRemovedType, UserRemovedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserTokenAddedType, UserTokenAddedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserImpersonatedType, eventstore.GenericEventMapper[UserImpersonatedEvent])
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserTokenRemovedType, UserTokenRemovedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserDomainClaimedType, DomainClaimedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserDomainClaimedSentType, DomainClaimedSentEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserUserNameChangedType, UsernameChangedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, MetadataSetType, MetadataSetEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, MetadataRemovedType, MetadataRemovedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, MetadataRemovedAllType, MetadataRemovedAllEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanAddedType, HumanAddedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanRegisteredType, HumanRegisteredEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanInitialCodeAddedType, HumanInitialCodeAddedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanInitialCodeSentType, HumanInitialCodeSentEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanInitializedCheckSucceededType, HumanInitializedCheckSucceededEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanInitializedCheckFailedType, HumanInitializedCheckFailedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanSignedOutType, HumanSignedOutEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanPasswordChangedType, HumanPasswordChangedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanPasswordCodeAddedType, HumanPasswordCodeAddedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanPasswordCodeSentType, eventstore.GenericEventMapper[HumanPasswordCodeSentEvent])
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanPasswordChangeSentType, HumanPasswordChangeSentEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanPasswordCheckSucceededType, HumanPasswordCheckSucceededEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanPasswordCheckFailedType, HumanPasswordCheckFailedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanPasswordHashUpdatedType, eventstore.GenericEventMapper[HumanPasswordHashUpdatedEvent])
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserIDPLinkAddedType, UserIDPLinkAddedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserIDPLinkRemovedType, UserIDPLinkRemovedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserIDPLinkCascadeRemovedType, UserIDPLinkCascadeRemovedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserIDPLoginCheckSucceededType, UserIDPCheckSucceededEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserIDPExternalIDMigratedType, eventstore.GenericEventMapper[UserIDPExternalIDMigratedEvent])
|
|
eventstore.RegisterFilterEventMapper(AggregateType, UserIDPExternalUsernameChangedType, eventstore.GenericEventMapper[UserIDPExternalUsernameEvent])
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanEmailChangedType, HumanEmailChangedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanEmailVerifiedType, HumanEmailVerifiedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanEmailVerificationFailedType, HumanEmailVerificationFailedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanEmailCodeAddedType, HumanEmailCodeAddedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanEmailCodeSentType, HumanEmailCodeSentEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanPhoneChangedType, HumanPhoneChangedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanPhoneRemovedType, HumanPhoneRemovedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanPhoneVerifiedType, HumanPhoneVerifiedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanPhoneVerificationFailedType, HumanPhoneVerificationFailedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanPhoneCodeAddedType, HumanPhoneCodeAddedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanPhoneCodeSentType, eventstore.GenericEventMapper[HumanPhoneCodeSentEvent])
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanProfileChangedType, HumanProfileChangedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanAvatarAddedType, HumanAvatarAddedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanAvatarRemovedType, HumanAvatarRemovedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanAddressChangedType, HumanAddressChangedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanMFAInitSkippedType, HumanMFAInitSkippedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanMFAOTPAddedType, HumanOTPAddedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanMFAOTPVerifiedType, HumanOTPVerifiedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanMFAOTPRemovedType, HumanOTPRemovedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanMFAOTPCheckSucceededType, HumanOTPCheckSucceededEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanMFAOTPCheckFailedType, HumanOTPCheckFailedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanMFAOTPCheckReusedType, eventstore.GenericEventMapper[HumanOTPCheckReusedEvent])
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanOTPSMSAddedType, eventstore.GenericEventMapper[HumanOTPSMSAddedEvent])
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanOTPSMSRemovedType, eventstore.GenericEventMapper[HumanOTPSMSRemovedEvent])
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanOTPSMSCodeAddedType, eventstore.GenericEventMapper[HumanOTPSMSCodeAddedEvent])
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanOTPSMSCodeSentType, eventstore.GenericEventMapper[HumanOTPSMSCodeSentEvent])
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanOTPSMSCheckSucceededType, eventstore.GenericEventMapper[HumanOTPSMSCheckSucceededEvent])
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanOTPSMSCheckFailedType, eventstore.GenericEventMapper[HumanOTPSMSCheckFailedEvent])
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanOTPEmailAddedType, eventstore.GenericEventMapper[HumanOTPEmailAddedEvent])
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanOTPEmailRemovedType, eventstore.GenericEventMapper[HumanOTPEmailRemovedEvent])
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanOTPEmailCodeAddedType, eventstore.GenericEventMapper[HumanOTPEmailCodeAddedEvent])
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanOTPEmailCodeSentType, eventstore.GenericEventMapper[HumanOTPEmailCodeSentEvent])
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanOTPEmailCheckSucceededType, eventstore.GenericEventMapper[HumanOTPEmailCheckSucceededEvent])
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanOTPEmailCheckFailedType, eventstore.GenericEventMapper[HumanOTPEmailCheckFailedEvent])
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanRecoveryCodesAddedType, eventstore.GenericEventMapper[HumanRecoveryCodesAddedEvent])
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanRecoveryCodesRemovedType, eventstore.GenericEventMapper[HumanRecoveryCodesRemovedEvent])
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanRecoveryCodeCheckSucceededType, eventstore.GenericEventMapper[HumanRecoveryCodeCheckSucceededEvent])
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanRecoveryCodeCheckFailedType, eventstore.GenericEventMapper[HumanRecoveryCodeCheckFailedEvent])
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanU2FTokenAddedType, HumanU2FAddedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanU2FTokenVerifiedType, HumanU2FVerifiedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanU2FTokenSignCountChangedType, HumanU2FSignCountChangedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanU2FTokenRemovedType, HumanU2FRemovedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanU2FTokenBeginLoginType, HumanU2FBeginLoginEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanU2FTokenCheckSucceededType, HumanU2FCheckSucceededEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanU2FTokenCheckFailedType, HumanU2FCheckFailedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanPasswordlessTokenAddedType, HumanPasswordlessAddedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanPasswordlessTokenVerifiedType, HumanPasswordlessVerifiedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanPasswordlessTokenSignCountChangedType, HumanPasswordlessSignCountChangedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanPasswordlessTokenRemovedType, HumanPasswordlessRemovedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanPasswordlessTokenBeginLoginType, HumanPasswordlessBeginLoginEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanPasswordlessTokenCheckSucceededType, HumanPasswordlessCheckSucceededEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanPasswordlessTokenCheckFailedType, HumanPasswordlessCheckFailedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanPasswordlessInitCodeAddedType, HumanPasswordlessInitCodeAddedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanPasswordlessInitCodeRequestedType, HumanPasswordlessInitCodeRequestedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanPasswordlessInitCodeSentType, HumanPasswordlessInitCodeSentEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanPasswordlessInitCodeCheckFailedType, HumanPasswordlessInitCodeCodeCheckFailedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanPasswordlessInitCodeCheckSucceededType, HumanPasswordlessInitCodeCodeCheckSucceededEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanRefreshTokenAddedType, HumanRefreshTokenAddedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanRefreshTokenRenewedType, HumanRefreshTokenRenewedEventEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanRefreshTokenRemovedType, HumanRefreshTokenRemovedEventEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, MachineAddedEventType, MachineAddedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, MachineChangedEventType, MachineChangedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, MachineKeyAddedEventType, MachineKeyAddedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, MachineKeyRemovedEventType, MachineKeyRemovedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, PersonalAccessTokenAddedType, PersonalAccessTokenAddedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, PersonalAccessTokenRemovedType, PersonalAccessTokenRemovedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, MachineSecretSetType, MachineSecretSetEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, MachineSecretRemovedType, MachineSecretRemovedEventMapper)
|
|
eventstore.RegisterFilterEventMapper(AggregateType, MachineSecretHashUpdatedType, eventstore.GenericEventMapper[MachineSecretHashUpdatedEvent])
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanInviteCodeAddedType, eventstore.GenericEventMapper[HumanInviteCodeAddedEvent])
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanInviteCodeSentType, eventstore.GenericEventMapper[HumanInviteCodeSentEvent])
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanInviteCheckSucceededType, eventstore.GenericEventMapper[HumanInviteCheckSucceededEvent])
|
|
eventstore.RegisterFilterEventMapper(AggregateType, HumanInviteCheckFailedType, eventstore.GenericEventMapper[HumanInviteCheckFailedEvent])
|
|
}
|