Skip to content

Commit

Permalink
fix: properly open recovery endpoints in browser if flow was initiate…
Browse files Browse the repository at this point in the history
…d via API
  • Loading branch information
aeneasr committed Oct 19, 2021
1 parent b6014ee commit 23c12e5
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 19 deletions.
46 changes: 36 additions & 10 deletions selfservice/strategy/link/strategy_recovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,26 +264,26 @@ func (s *Strategy) recoveryIssueSession(w http.ResponseWriter, r *http.Request,
Valid: true,
}
if err := s.d.RecoveryFlowPersister().UpdateRecoveryFlow(r.Context(), f); err != nil {
return s.HandleRecoveryError(w, r, f, nil, err)
return s.retryRecoveryFlowWithError(w, r, flow.TypeBrowser, err)
}

sess, _ := session.NewActiveSession(id, s.d.Config(r.Context()), time.Now().UTC(), identity.CredentialsTypeRecoveryLink)
if err := s.d.SessionManager().UpsertAndIssueCookie(r.Context(), w, r, sess); err != nil {
return s.HandleRecoveryError(w, r, f, nil, err)
return s.retryRecoveryFlowWithError(w, r, flow.TypeBrowser, err)
}

sf, err := s.d.SettingsHandler().NewFlow(w, r, sess.Identity, flow.TypeBrowser)
if err != nil {
return s.HandleRecoveryError(w, r, f, nil, err)
return s.retryRecoveryFlowWithError(w, r, flow.TypeBrowser, err)
}

if err := s.d.RecoveryExecutor().PostRecoveryHook(w, r, f, sess); err != nil {
return s.HandleRecoveryError(w, r, f, nil, err)
return s.retryRecoveryFlowWithError(w, r, flow.TypeBrowser, err)
}

sf.UI.Messages.Set(text.NewRecoverySuccessful(time.Now().Add(s.d.Config(r.Context()).SelfServiceFlowSettingsPrivilegedSessionMaxAge())))
if err := s.d.SettingsFlowPersister().UpdateSettingsFlow(r.Context(), sf); err != nil {
return s.HandleRecoveryError(w, r, f, nil, err)
return s.retryRecoveryFlowWithError(w, r, flow.TypeBrowser, err)
}

http.Redirect(w, r, sf.AppendTo(s.d.Config(r.Context()).SelfServiceFlowSettingsUI()).String(), http.StatusSeeOther)
Expand All @@ -297,29 +297,29 @@ func (s *Strategy) recoveryUseToken(w http.ResponseWriter, r *http.Request, body
return s.retryRecoveryFlowWithMessage(w, r, flow.TypeBrowser, text.NewErrorValidationRecoveryTokenInvalidOrAlreadyUsed())
}

return s.HandleRecoveryError(w, r, nil, body, err)
return s.retryRecoveryFlowWithError(w, r, flow.TypeBrowser, err)
}

var f *recovery.Flow
if !token.FlowID.Valid {
f, err = recovery.NewFlow(s.d.Config(r.Context()), time.Until(token.ExpiresAt), s.d.GenerateCSRFToken(r),
r, s.d.RecoveryStrategies(r.Context()), flow.TypeBrowser)
if err != nil {
return s.HandleRecoveryError(w, r, nil, body, err)
return s.retryRecoveryFlowWithError(w, r, flow.TypeBrowser, err)
}

if err := s.d.RecoveryFlowPersister().CreateRecoveryFlow(r.Context(), f); err != nil {
return s.HandleRecoveryError(w, r, nil, body, err)
return s.retryRecoveryFlowWithError(w, r, flow.TypeBrowser, err)
}
} else {
f, err = s.d.RecoveryFlowPersister().GetRecoveryFlow(r.Context(), token.FlowID.UUID)
if err != nil {
return s.HandleRecoveryError(w, r, nil, body, err)
return s.retryRecoveryFlowWithError(w, r, flow.TypeBrowser, err)
}
}

if err := token.Valid(); err != nil {
return s.HandleRecoveryError(w, r, f, body, err)
return s.retryRecoveryFlowWithError(w, r, flow.TypeBrowser, err)
}

recovered, err := s.d.IdentityPool().GetIdentity(r.Context(), token.RecoveryAddress.IdentityID)
Expand Down Expand Up @@ -360,6 +360,32 @@ func (s *Strategy) retryRecoveryFlowWithMessage(w http.ResponseWriter, r *http.R
return errors.WithStack(flow.ErrCompletedByStrategy)
}

func (s *Strategy) retryRecoveryFlowWithError(w http.ResponseWriter, r *http.Request, ft flow.Type, recErr error) error {
s.d.Logger().WithRequest(r).WithError( recErr).Debug("A recovery flow is being retried because a validation error occurred.")

req, err := recovery.NewFlow(s.d.Config(r.Context()), s.d.Config(r.Context()).SelfServiceFlowRecoveryRequestLifespan(), s.d.CSRFHandler().RegenerateToken(w,r), r, s.d.RecoveryStrategies(r.Context()), ft)
if err != nil {
return err
}

if err := req.UI.ParseError(node.RecoveryLinkGroup,recErr); err != nil {
return err
}

if err := s.d.RecoveryFlowPersister().CreateRecoveryFlow(r.Context(), req); err != nil {
return err
}

if ft == flow.TypeBrowser {
http.Redirect(w, r, req.AppendTo(s.d.Config(r.Context()).SelfServiceFlowRecoveryUI()).String(), http.StatusSeeOther)
} else {
http.Redirect(w, r, urlx.CopyWithQuery(urlx.AppendPaths(s.d.Config(r.Context()).SelfPublicURL(r),
recovery.RouteGetFlow), url.Values{"id": {req.ID.String()}}).String(), http.StatusSeeOther)
}

return errors.WithStack(flow.ErrCompletedByStrategy)
}

func (s *Strategy) recoveryHandleFormSubmission(w http.ResponseWriter, r *http.Request, f *recovery.Flow) error {
body, err := s.decodeRecovery(r)
if err != nil {
Expand Down
45 changes: 36 additions & 9 deletions selfservice/strategy/link/strategy_verification.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,28 +194,28 @@ func (s *Strategy) verificationUseToken(w http.ResponseWriter, r *http.Request,
return s.retryVerificationFlowWithMessage(w, r, flow.TypeBrowser, text.NewErrorValidationVerificationTokenInvalidOrAlreadyUsed())
}

return s.handleVerificationError(w, r, nil, body, err)
return s.retryVerificationFlowWithError(w, r, flow.TypeBrowser, err)
}

var f *verification.Flow
if !token.FlowID.Valid {
f, err = verification.NewFlow(s.d.Config(r.Context()), s.d.Config(r.Context()).SelfServiceFlowVerificationRequestLifespan(), s.d.GenerateCSRFToken(r), r, s.d.VerificationStrategies(r.Context()), flow.TypeBrowser)
if err != nil {
return s.handleVerificationError(w, r, nil, body, err)
return s.retryVerificationFlowWithError(w, r, flow.TypeBrowser, err)
}

if err := s.d.VerificationFlowPersister().CreateVerificationFlow(r.Context(), f); err != nil {
return s.handleVerificationError(w, r, nil, body, err)
return s.retryVerificationFlowWithError(w, r, flow.TypeBrowser, err)
}
} else {
f, err = s.d.VerificationFlowPersister().GetVerificationFlow(r.Context(), token.FlowID.UUID)
if err != nil {
return s.handleVerificationError(w, r, nil, body, err)
return s.retryVerificationFlowWithError(w, r, flow.TypeBrowser, err)
}
}

if err := token.Valid(); err != nil {
return s.handleVerificationError(w, r, f, body, err)
return s.retryVerificationFlowWithError(w, r, flow.TypeBrowser, err)
}

f.UI.Messages.Clear()
Expand All @@ -224,16 +224,16 @@ func (s *Strategy) verificationUseToken(w http.ResponseWriter, r *http.Request,
f.SetCSRFToken(flow.GetCSRFToken(s.d, w, r, f.Type))
f.UI.Messages.Set(text.NewInfoSelfServiceVerificationSuccessful())
if err := s.d.VerificationFlowPersister().UpdateVerificationFlow(r.Context(), f); err != nil {
return s.handleVerificationError(w, r, f, body, err)
return s.retryVerificationFlowWithError(w, r, flow.TypeBrowser, err)
}

i, err := s.d.IdentityPool().GetIdentity(r.Context(), token.VerifiableAddress.IdentityID)
if err != nil {
return s.handleVerificationError(w, r, f, body, err)
return s.retryVerificationFlowWithError(w, r, flow.TypeBrowser, err)
}

if err := s.d.VerificationExecutor().PostVerificationHook(w, r, f, i); err != nil {
return s.handleVerificationError(w, r, f, body, err)
return s.retryVerificationFlowWithError(w, r, flow.TypeBrowser, err)
}

address := token.VerifiableAddress
Expand All @@ -242,7 +242,7 @@ func (s *Strategy) verificationUseToken(w http.ResponseWriter, r *http.Request,
address.VerifiedAt = &verifiedAt
address.Status = identity.VerifiableAddressStatusCompleted
if err := s.d.PrivilegedIdentityPool().UpdateVerifiableAddress(r.Context(), address); err != nil {
return s.handleVerificationError(w, r, f, body, err)
return s.retryVerificationFlowWithError(w, r, flow.TypeBrowser, err)
}

defaultRedirectURL := s.d.Config(r.Context()).SelfServiceFlowVerificationReturnTo(f.AppendTo(s.d.Config(r.Context()).SelfServiceFlowVerificationUI()))
Expand Down Expand Up @@ -292,3 +292,30 @@ func (s *Strategy) retryVerificationFlowWithMessage(w http.ResponseWriter, r *ht

return errors.WithStack(flow.ErrCompletedByStrategy)
}

func (s *Strategy) retryVerificationFlowWithError(w http.ResponseWriter, r *http.Request, ft flow.Type, verErr error) error {
s.d.Logger().WithRequest(r).WithError(verErr).Debug("A verification flow is being retried because an error occurred.")

f, err := verification.NewFlow(s.d.Config(r.Context()),
s.d.Config(r.Context()).SelfServiceFlowVerificationRequestLifespan(), s.d.CSRFHandler().RegenerateToken(w, r), r, s.d.VerificationStrategies(r.Context()), ft)
if err != nil {
return s.handleVerificationError(w, r, f, nil, err)
}

if err := f.UI.ParseError(node.VerificationLinkGroup, verErr); err != nil {
return err
}

if err := s.d.VerificationFlowPersister().CreateVerificationFlow(r.Context(), f); err != nil {
return s.handleVerificationError(w, r, f, nil, err)
}

if ft == flow.TypeBrowser {
http.Redirect(w, r, f.AppendTo(s.d.Config(r.Context()).SelfServiceFlowVerificationUI()).String(), http.StatusSeeOther)
} else {
http.Redirect(w, r, urlx.CopyWithQuery(urlx.AppendPaths(s.d.Config(r.Context()).SelfPublicURL(r),
verification.RouteGetFlow), url.Values{"id": {f.ID.String()}}).String(), http.StatusSeeOther)
}

return errors.WithStack(flow.ErrCompletedByStrategy)
}

0 comments on commit 23c12e5

Please sign in to comment.