This repository has been archived by the owner on Mar 1, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
duo.go
86 lines (74 loc) · 2.08 KB
/
duo.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
package idp
import (
"context"
"errors"
"fmt"
"time"
"github.com/chromedp/chromedp"
"github.com/fatih/color"
)
func submitAuthMethod(authMethod string) error {
t, cancel := context.WithTimeout(chrome.Ctxt, 30*time.Second)
timeoutContext = t
defer cancel()
_, err := waitForFrame()
if err != nil {
return err
}
if err := clickAuthMethod(authMethod); err != nil {
return err
}
return nil
}
func waitForFrame() (bool, error) {
// busy wait until the frame loads or > ~40seconds
// for multi-device users the frame load might be "partial" w/ a checkbox available
// before the buttons, so we check for both to be safe.
for i := 0; i < 20; i++ {
// "Remember me.." checkbox
if ok := isPresent(`//input[@name='dampen_choice']`); ok {
break
}
time.Sleep(1 * time.Second)
}
// busy wait for a button
for i := 0; i < 20; i++ {
if ok := isPresent(`//button[contains(., 'Push') or contains(., 'Call')]`); ok {
return ok, nil
}
time.Sleep(1 * time.Second)
}
return false, errors.New("Timeout waiting for DUO frame.")
}
func clickAuthMethod(method string) error {
var buf []byte
m := make(map[string]string)
m["push"] = "//button[contains(., 'Push')]"
m["call"] = "//button[contains(., 'Call')]"
js := fmt.Sprintf(`
doc = document.querySelector('iframe[id="duo_iframe"]').contentWindow.document
document.evaluate("%s", doc).iterateNext().click()
`, m[method])
//check if an auto-push/call is actually configured
if isPresent(`//small[@class='used-automatically']`) {
color.Yellow("(chrome) Auto-selected DUO method used, ignoring configured method '%s'.\n", method)
return nil
}
return chrome.C.Run(timeoutContext,
chromedp.Evaluate(js, &buf, chromedp.EvalIgnoreExceptions),
)
}
func isPresent(xpath string) bool {
var res interface{}
js := fmt.Sprintf(`
f = function(sel) {
doc = document.querySelector('iframe[id="duo_iframe"]').contentWindow.document
return document.evaluate(sel, doc).iterateNext() !== null
}
f("%s")
`, xpath)
if err := chrome.C.Run(timeoutContext, chromedp.Evaluate(js, &res)); err != nil {
return false
}
return res.(bool)
}