Skip to content

Commit

Permalink
feat: allow admin to create API code recovery flows (#3939)
Browse files Browse the repository at this point in the history
  • Loading branch information
zepatrik committed Jun 4, 2024
1 parent fbbac77 commit 25d1ecd
Show file tree
Hide file tree
Showing 12 changed files with 196 additions and 75 deletions.
1 change: 1 addition & 0 deletions internal/client-go/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
Expand Down
37 changes: 37 additions & 0 deletions internal/client-go/model_create_recovery_code_for_identity_body.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions selfservice/flow/type.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,11 @@ func (t Type) IsBrowser() bool {
func (t Type) IsAPI() bool {
return t == TypeAPI
}

func (t Type) Valid() bool {
switch t {
case TypeAPI, TypeBrowser:
return true
}
return false
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"error": {
"code": 400,
"message": "The request was malformed or contained invalid parameters",
"reason": "Value from \"expires_in\" must result to a future time: -1h",
"reason": "Value from \"expires_in\" must result to a future time: -1h0m0s",
"status": "Bad Request"
}
}
9 changes: 3 additions & 6 deletions selfservice/strategy/code/strategy_recovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -161,9 +161,8 @@ func (s *Strategy) Recover(w http.ResponseWriter, r *http.Request, f *recovery.F
}

switch recoveryFlow.State {
case flow.StateChooseMethod:
fallthrough
case flow.StateEmailSent:
case flow.StateChooseMethod,
flow.StateEmailSent:
return s.recoveryHandleFormSubmission(w, r, recoveryFlow, body)
case flow.StatePassedChallenge:
// was already handled, do not allow retry
Expand Down Expand Up @@ -237,9 +236,7 @@ func (s *Strategy) recoveryIssueSession(w http.ResponseWriter, r *http.Request,

if s.deps.Config().UseContinueWithTransitions(ctx) {
switch {
case f.Type.IsAPI():
fallthrough
case x.IsJSONRequest(r):
case f.Type.IsAPI(), x.IsJSONRequest(r):
f.ContinueWith = append(f.ContinueWith, flow.NewContinueWithSettingsUI(sf))
s.deps.Writer().Write(w, r, f)
default:
Expand Down
22 changes: 19 additions & 3 deletions selfservice/strategy/code/strategy_recovery_admin.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,13 @@ type createRecoveryCodeForIdentityBody struct {
// - 1m
// - 1s
ExpiresIn string `json:"expires_in"`

// Flow Type
//
// The flow type for the recovery flow. Defaults to browser.
//
// required: false
FlowType *flow.Type `json:"flow_type"`
}

// Recovery Code for Identity
Expand Down Expand Up @@ -149,12 +156,21 @@ func (s *Strategy) createRecoveryCodeForIdentity(w http.ResponseWriter, r *http.
}
}

if time.Now().Add(expiresIn).Before(time.Now()) {
s.deps.Writer().WriteError(w, r, errors.WithStack(herodot.ErrBadRequest.WithReasonf(`Value from "expires_in" must result to a future time: %s`, p.ExpiresIn)))
if expiresIn <= 0 {
s.deps.Writer().WriteError(w, r, errors.WithStack(herodot.ErrBadRequest.WithReasonf(`Value from "expires_in" must result to a future time: %s`, expiresIn)))
return
}

flowType := flow.TypeBrowser
if p.FlowType != nil {
flowType = *p.FlowType
}
if !flowType.Valid() {
s.deps.Writer().WriteError(w, r, errors.WithStack(herodot.ErrBadRequest.WithReasonf(`Value from "flow_type" is not valid: %q`, flowType)))
return
}

recoveryFlow, err := recovery.NewFlow(config, expiresIn, s.deps.GenerateCSRFToken(r), r, s, flow.TypeBrowser)
recoveryFlow, err := recovery.NewFlow(config, expiresIn, s.deps.GenerateCSRFToken(r), r, s, flowType)
if err != nil {
s.deps.Writer().WriteError(w, r, err)
return
Expand Down
Loading

0 comments on commit 25d1ecd

Please sign in to comment.