@@ -98,6 +98,15 @@ func (ac *Client) follow(ctx context.Context, req *http.Request) (string, error)
98
98
} else if docIsLogin (doc ) {
99
99
logger .WithField ("type" , "login" ).Debug ("doc detect" )
100
100
handler = ac .handleLogin
101
+ } else if docIsCheckWebAuthn (doc ) {
102
+ logger .WithField ("type" , "check-webauthn" ).Debug ("doc detect" )
103
+ handler = ac .handleCheckWebAuthn
104
+ } else if docIsFormSelectDevice (doc ) {
105
+ logger .WithField ("type" , "select-device" ).Debug ("doc detect" )
106
+ handler = ac .handleFormSelectDevice
107
+ } else if docIsAuthPostback (doc ) {
108
+ logger .WithField ("type" , "auth-postback" ).Debug ("doc detect" )
109
+ handler = ac .handleFormRedirect
101
110
} else if docIsOTP (doc ) {
102
111
logger .WithField ("type" , "otp" ).Debug ("doc detect" )
103
112
handler = ac .handleOTP
@@ -148,6 +157,18 @@ func (ac *Client) handleLogin(ctx context.Context, doc *goquery.Document, _ *url
148
157
return ctx , req , err
149
158
}
150
159
160
+ func (ac * Client ) handleCheckWebAuthn (ctx context.Context , doc * goquery.Document , requestURL * url.URL ) (context.Context , * http.Request , error ) {
161
+ form , err := page .NewFormFromDocument (doc , "form" )
162
+ if err != nil {
163
+ return ctx , nil , errors .Wrap (err , "error extracting login form" )
164
+ }
165
+
166
+ form .Values .Set ("isWebAuthnSupportedByBrowser" , "false" )
167
+
168
+ req , err := form .BuildRequest ()
169
+ return ctx , req , err
170
+ }
171
+
151
172
func (ac * Client ) handleOTP (ctx context.Context , doc * goquery.Document , requestURL * url.URL ) (context.Context , * http.Request , error ) {
152
173
form , err := page .NewFormFromDocument (doc , "#otp-form" )
153
174
if err != nil {
@@ -235,6 +256,29 @@ func (ac *Client) handleRefresh(ctx context.Context, doc *goquery.Document, _ *u
235
256
return ctx , req , err
236
257
}
237
258
259
+ func (ac * Client ) handleFormSelectDevice (ctx context.Context , doc * goquery.Document , requestURL * url.URL ) (context.Context , * http.Request , error ) {
260
+ var deviceMap = findDeviceMap (doc )
261
+ deviceNameList := make ([]string , len (deviceMap ))
262
+ i := 0
263
+ for key := range deviceMap {
264
+ deviceNameList [i ] = key
265
+ i ++
266
+ }
267
+ var chooseDevice = prompter .Choose ("Select which MFA Device to use" , deviceNameList )
268
+
269
+ form , err := page .NewFormFromDocument (doc , "" )
270
+ if err != nil {
271
+ return ctx , nil , errors .Wrap (err , "error extracting select device form" )
272
+ }
273
+
274
+ form .Values .Set ("deviceId" , deviceMap [deviceNameList [chooseDevice ]])
275
+ form .URL = makeAbsoluteURL (form .URL , makeBaseURL (requestURL ))
276
+
277
+ logger .WithField ("value" , form .Values .Encode ()).Debug ("Select Device" )
278
+ req , err := form .BuildRequest ()
279
+ return ctx , req , err
280
+ }
281
+
238
282
func (ac * Client ) handleFormRedirect (ctx context.Context , doc * goquery.Document , _ * url.URL ) (context.Context , * http.Request , error ) {
239
283
form , err := page .NewFormFromDocument (doc , "" )
240
284
if err != nil {
@@ -262,6 +306,14 @@ func docIsOTP(doc *goquery.Document) bool {
262
306
return doc .Has ("form#otp-form" ).Size () == 1
263
307
}
264
308
309
+ func docIsCheckWebAuthn (doc * goquery.Document ) bool {
310
+ return doc .Has ("input[name=\" isWebAuthnSupportedByBrowser\" ]" ).Size () == 1
311
+ }
312
+
313
+ func docIsAuthPostback (doc * goquery.Document ) bool {
314
+ return doc .Has ("form#form1" ).Size () == 1 && doc .Has ("form#reponseView" ).Size () == 0
315
+ }
316
+
265
317
func docIsSwipe (doc * goquery.Document ) bool {
266
318
return doc .Has ("form#form1" ).Size () == 1 && doc .Has ("form#reponseView" ).Size () == 1
267
319
}
@@ -294,6 +346,10 @@ func docIsFormRedirectToTarget(doc *goquery.Document, target string) bool {
294
346
return doc .Find (urlForm ).Size () == 1
295
347
}
296
348
349
+ func docIsFormSelectDevice (doc * goquery.Document ) bool {
350
+ return doc .Has ("form[name=\" device-form\" ]" ).Size () == 1
351
+ }
352
+
297
353
func docIsRefresh (doc * goquery.Document ) bool {
298
354
return doc .Has ("meta[http-equiv=\" refresh\" ]" ).Size () == 1
299
355
}
@@ -309,3 +365,23 @@ func makeAbsoluteURL(v string, base string) string {
309
365
}
310
366
return v
311
367
}
368
+
369
+ func makeBaseURL (url * url.URL ) string {
370
+ return url .Scheme + "://" + url .Hostname ()
371
+ }
372
+
373
+ func findDeviceMap (doc * goquery.Document ) map [string ]string {
374
+ deviceList := make (map [string ]string )
375
+
376
+ doc .Find ("ul.device-list > li" ).Each (func (_ int , s * goquery.Selection ) {
377
+ deviceId , _ := s .Attr ("data-id" )
378
+ deviceName , _ := s .Find ("a > div.device-name" ).Html ()
379
+ if deviceName == "" {
380
+ deviceName , _ = s .Find ("button > div.device-name" ).Html ()
381
+ }
382
+
383
+ logger .WithField ("device name" , deviceName ).WithField ("device id" , deviceId ).Debug ("Select Device" )
384
+ deviceList [deviceName ] = deviceId
385
+ })
386
+ return deviceList
387
+ }
0 commit comments