From 9ff845311c957394924f8e77f4b5f1bb0f2e75cd Mon Sep 17 00:00:00 2001 From: Frederic Jahn Date: Mon, 26 Aug 2024 15:22:43 +0200 Subject: [PATCH] fix: create new flow for every request Create a new flow for every request, because the flowBuilder is not save for concurrent usage. --- backend/flow_api/flow/flows.go | 162 ++++++++++++++++++--------------- backend/flow_api/handler.go | 8 +- 2 files changed, 92 insertions(+), 78 deletions(-) diff --git a/backend/flow_api/flow/flows.go b/backend/flow_api/flow/flows.go index cd04a46f8..2405c9bd6 100644 --- a/backend/flow_api/flow/flows.go +++ b/backend/flow_api/flow/flows.go @@ -76,80 +76,92 @@ var UserDetailsSubFlow = flowpilot.NewSubFlow(shared.FlowUserDetails). user_details.SkipEmail{}). MustBuild() -var LoginFlow = flowpilot.NewFlow(shared.FlowLogin). - State(shared.StateSuccess). - InitialState(shared.StatePreflight, shared.StateLoginInit). - ErrorState(shared.StateError). - BeforeState(shared.StateLoginInit, - login.WebauthnGenerateRequestOptionsForConditionalUi{}). - BeforeState(shared.StateSuccess, - shared.IssueSession{}, - shared.GetUserData{}). - AfterState(shared.StateOnboardingVerifyPasskeyAttestation, - shared.WebauthnCredentialSave{}). - AfterState(shared.StatePasscodeConfirmation, - shared.EmailPersistVerifiedStatus{}). - AfterState(shared.StatePasswordCreation, - shared.PasswordSave{}). - AfterState(shared.StateOnboardingEmail, login.CreateEmail{}). - AfterState(shared.StatePasscodeConfirmation, login.CreateEmail{}). - AfterFlow(shared.FlowCredentialUsage, login.ScheduleOnboardingStates{}). - SubFlows( - CapabilitiesSubFlow, - CredentialUsageSubFlow, - CredentialOnboardingSubFlow, - UserDetailsSubFlow). - TTL(24 * time.Hour) +func NewLoginFlow(debug bool) flowpilot.Flow { + return flowpilot.NewFlow(shared.FlowLogin). + State(shared.StateSuccess). + InitialState(shared.StatePreflight, shared.StateLoginInit). + ErrorState(shared.StateError). + BeforeState(shared.StateLoginInit, + login.WebauthnGenerateRequestOptionsForConditionalUi{}). + BeforeState(shared.StateSuccess, + shared.IssueSession{}, + shared.GetUserData{}). + AfterState(shared.StateOnboardingVerifyPasskeyAttestation, + shared.WebauthnCredentialSave{}). + AfterState(shared.StatePasscodeConfirmation, + shared.EmailPersistVerifiedStatus{}). + AfterState(shared.StatePasswordCreation, + shared.PasswordSave{}). + AfterState(shared.StateOnboardingEmail, login.CreateEmail{}). + AfterState(shared.StatePasscodeConfirmation, login.CreateEmail{}). + AfterFlow(shared.FlowCredentialUsage, login.ScheduleOnboardingStates{}). + SubFlows( + CapabilitiesSubFlow, + CredentialUsageSubFlow, + CredentialOnboardingSubFlow, + UserDetailsSubFlow). + TTL(24 * time.Hour). + Debug(debug). + MustBuild() +} -var RegistrationFlow = flowpilot.NewFlow(shared.FlowRegistration). - State(shared.StateRegistrationInit, - registration.RegisterLoginIdentifier{}, - shared.ThirdPartyOAuth{}). - State(shared.StateThirdParty, - shared.ExchangeToken{}). - State(shared.StateSuccess). - InitialState(shared.StatePreflight, - shared.StateRegistrationInit). - ErrorState(shared.StateError). - BeforeState(shared.StateSuccess, - shared.GetUserData{}, - registration.CreateUser{}, - shared.IssueSession{}). - SubFlows( - CapabilitiesSubFlow, - CredentialUsageSubFlow, - CredentialOnboardingSubFlow, - UserDetailsSubFlow). - TTL(24 * time.Hour) +func NewRegistrationFlow(debug bool) flowpilot.Flow { + return flowpilot.NewFlow(shared.FlowRegistration). + State(shared.StateRegistrationInit, + registration.RegisterLoginIdentifier{}, + shared.ThirdPartyOAuth{}). + State(shared.StateThirdParty, + shared.ExchangeToken{}). + State(shared.StateSuccess). + InitialState(shared.StatePreflight, + shared.StateRegistrationInit). + ErrorState(shared.StateError). + BeforeState(shared.StateSuccess, + shared.GetUserData{}, + registration.CreateUser{}, + shared.IssueSession{}). + SubFlows( + CapabilitiesSubFlow, + CredentialUsageSubFlow, + CredentialOnboardingSubFlow, + UserDetailsSubFlow). + TTL(24 * time.Hour). + Debug(debug). + MustBuild() +} -var ProfileFlow = flowpilot.NewFlow(shared.FlowProfile). - State(shared.StateProfileInit, - profile.AccountDelete{}, - profile.EmailCreate{}, - profile.EmailDelete{}, - profile.EmailSetPrimary{}, - profile.EmailVerify{}, - profile.PasswordCreate{}, - profile.PasswordUpdate{}, - profile.PasswordDelete{}, - profile.UsernameCreate{}, - profile.UsernameUpdate{}, - profile.UsernameDelete{}, - profile.WebauthnCredentialRename{}, - profile.WebauthnCredentialCreate{}, - profile.WebauthnCredentialDelete{}, - ). - State(shared.StateProfileWebauthnCredentialVerification, - profile.WebauthnVerifyAttestationResponse{}, - shared.Back{}). - State(shared.StateProfileAccountDeleted). - InitialState(shared.StatePreflight, shared.StateProfileInit). - ErrorState(shared.StateError). - BeforeEachAction(profile.RefreshSessionUser{}). - BeforeState(shared.StateProfileInit, profile.GetProfileData{}). - AfterState(shared.StateProfileWebauthnCredentialVerification, shared.WebauthnCredentialSave{}). - AfterState(shared.StatePasscodeConfirmation, shared.EmailPersistVerifiedStatus{}). - SubFlows( - CapabilitiesSubFlow, - CredentialUsageSubFlow). - TTL(24 * time.Hour) +func NewProfileFlow(debug bool) flowpilot.Flow { + return flowpilot.NewFlow(shared.FlowProfile). + State(shared.StateProfileInit, + profile.AccountDelete{}, + profile.EmailCreate{}, + profile.EmailDelete{}, + profile.EmailSetPrimary{}, + profile.EmailVerify{}, + profile.PasswordCreate{}, + profile.PasswordUpdate{}, + profile.PasswordDelete{}, + profile.UsernameCreate{}, + profile.UsernameUpdate{}, + profile.UsernameDelete{}, + profile.WebauthnCredentialRename{}, + profile.WebauthnCredentialCreate{}, + profile.WebauthnCredentialDelete{}, + ). + State(shared.StateProfileWebauthnCredentialVerification, + profile.WebauthnVerifyAttestationResponse{}, + shared.Back{}). + State(shared.StateProfileAccountDeleted). + InitialState(shared.StatePreflight, shared.StateProfileInit). + ErrorState(shared.StateError). + BeforeEachAction(profile.RefreshSessionUser{}). + BeforeState(shared.StateProfileInit, profile.GetProfileData{}). + AfterState(shared.StateProfileWebauthnCredentialVerification, shared.WebauthnCredentialSave{}). + AfterState(shared.StatePasscodeConfirmation, shared.EmailPersistVerifiedStatus{}). + SubFlows( + CapabilitiesSubFlow, + CredentialUsageSubFlow). + TTL(24 * time.Hour). + Debug(debug). + MustBuild() +} diff --git a/backend/flow_api/handler.go b/backend/flow_api/handler.go index 6a8ab6390..bb98321d7 100644 --- a/backend/flow_api/handler.go +++ b/backend/flow_api/handler.go @@ -39,15 +39,17 @@ type FlowPilotHandler struct { } func (h *FlowPilotHandler) RegistrationFlowHandler(c echo.Context) error { - return h.executeFlow(c, flow.RegistrationFlow.Debug(h.Cfg.Debug).MustBuild()) + registrationFlow := flow.NewRegistrationFlow(h.Cfg.Debug) + return h.executeFlow(c, registrationFlow) } func (h *FlowPilotHandler) LoginFlowHandler(c echo.Context) error { - return h.executeFlow(c, flow.LoginFlow.Debug(h.Cfg.Debug).MustBuild()) + loginFlow := flow.NewLoginFlow(h.Cfg.Debug) + return h.executeFlow(c, loginFlow) } func (h *FlowPilotHandler) ProfileFlowHandler(c echo.Context) error { - profileFlow := flow.ProfileFlow.Debug(h.Cfg.Debug).MustBuild() + profileFlow := flow.NewProfileFlow(h.Cfg.Debug) if err := h.validateSession(c); err != nil { flowResult := profileFlow.ResultFromError(err)