/
setup_oob_otp.go
146 lines (123 loc) · 4.7 KB
/
setup_oob_otp.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
package authflowv2
import (
"fmt"
"net/http"
"github.com/authgear/authgear-server/pkg/api/model"
handlerwebapp "github.com/authgear/authgear-server/pkg/auth/handler/webapp"
"github.com/authgear/authgear-server/pkg/auth/handler/webapp/viewmodels"
"github.com/authgear/authgear-server/pkg/auth/webapp"
"github.com/authgear/authgear-server/pkg/lib/authenticationflow/declarative"
"github.com/authgear/authgear-server/pkg/lib/config"
"github.com/authgear/authgear-server/pkg/util/httproute"
"github.com/authgear/authgear-server/pkg/util/template"
"github.com/authgear/authgear-server/pkg/util/validation"
)
var TemplateWebAuthflowSetupOOBOTPHTML = template.RegisterHTML(
"web/authflowv2/setup_oob_otp.html",
handlerwebapp.Components...,
)
var AuthflowSetupOOBOTPSchema = validation.NewSimpleSchema(`
{
"type": "object",
"properties": {
"x_target": { "type": "string" }
},
"required": ["x_target"]
}
`)
func ConfigureAuthflowV2SetupOOBOTPRoute(route httproute.Route) httproute.Route {
return route.
WithMethods("OPTIONS", "POST", "GET").
WithPathPattern(AuthflowV2RouteSetupOOBOTP)
}
type AuthflowSetupOOBOTPViewModel struct {
OOBAuthenticatorType model.AuthenticatorType
Channel model.AuthenticatorOOBChannel
}
type AuthflowV2SetupOOBOTPHandler struct {
Controller *handlerwebapp.AuthflowController
BaseViewModel *viewmodels.BaseViewModeler
Renderer handlerwebapp.Renderer
}
func (h *AuthflowV2SetupOOBOTPHandler) GetData(w http.ResponseWriter, r *http.Request, s *webapp.Session, screen *webapp.AuthflowScreenWithFlowResponse) (map[string]interface{}, error) {
data := make(map[string]interface{})
baseViewModel := h.BaseViewModel.ViewModelForAuthFlow(r, w)
viewmodels.Embed(data, baseViewModel)
index := *screen.Screen.TakenBranchIndex
screenData := screen.StateTokenFlowResponse.Action.Data.(declarative.IntentSignupFlowStepCreateAuthenticatorData)
option := screenData.Options[index]
var oobAuthenticatorType model.AuthenticatorType
switch option.Authentication {
case config.AuthenticationFlowAuthenticationPrimaryOOBOTPEmail:
oobAuthenticatorType = model.AuthenticatorTypeOOBEmail
case config.AuthenticationFlowAuthenticationSecondaryOOBOTPEmail:
oobAuthenticatorType = model.AuthenticatorTypeOOBEmail
case config.AuthenticationFlowAuthenticationPrimaryOOBOTPSMS:
oobAuthenticatorType = model.AuthenticatorTypeOOBSMS
case config.AuthenticationFlowAuthenticationSecondaryOOBOTPSMS:
oobAuthenticatorType = model.AuthenticatorTypeOOBSMS
default:
panic(fmt.Errorf("unexpected authentication: %v", option.Authentication))
}
channel := screen.Screen.TakenChannel
screenViewModel := AuthflowSetupOOBOTPViewModel{
OOBAuthenticatorType: oobAuthenticatorType,
Channel: channel,
}
viewmodels.Embed(data, screenViewModel)
authentication := getTakenBranchSignupCreateAuthenticatorAuthentication(screen)
branchFilter := func(branches []viewmodels.AuthflowBranch) []viewmodels.AuthflowBranch {
filtered := []viewmodels.AuthflowBranch{}
for _, branch := range branches {
if branch.Authentication == authentication {
// Hide oob otp branches of same type
continue
}
filtered = append(filtered, branch)
}
return filtered
}
branchViewModel := viewmodels.NewAuthflowBranchViewModel(screen, branchFilter)
viewmodels.Embed(data, branchViewModel)
return data, nil
}
func (h *AuthflowV2SetupOOBOTPHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
var handlers handlerwebapp.AuthflowControllerHandlers
handlers.Get(func(s *webapp.Session, screen *webapp.AuthflowScreenWithFlowResponse) error {
data, err := h.GetData(w, r, s, screen)
if err != nil {
return err
}
h.Renderer.RenderHTML(w, r, TemplateWebAuthflowSetupOOBOTPHTML, data)
return nil
})
handlers.PostAction("", func(s *webapp.Session, screen *webapp.AuthflowScreenWithFlowResponse) error {
err := AuthflowSetupOOBOTPSchema.Validator().ValidateValue(handlerwebapp.FormToJSON(r.Form))
if err != nil {
return err
}
index := *screen.Screen.TakenBranchIndex
screenData := screen.StateTokenFlowResponse.Action.Data.(declarative.IntentSignupFlowStepCreateAuthenticatorData)
option := screenData.Options[index]
authentication := option.Authentication
channel := screen.Screen.TakenChannel
target := r.Form.Get("x_target")
if channel == "" {
channel = option.Channels[0]
}
input := map[string]interface{}{
"authentication": authentication,
"target": target,
"channel": channel,
}
result, err := h.Controller.AdvanceWithInput(r, s, screen, input, &handlerwebapp.AdvanceOptions{
InheritTakenBranchState: true,
})
if err != nil {
return err
}
result.WriteResponse(w, r)
return nil
})
h.Controller.HandleStep(w, r, &handlers)
}