diff --git a/core/EasyConnectClient.go b/core/EasyConnectClient.go index a20aced..275a556 100644 --- a/core/EasyConnectClient.go +++ b/core/EasyConnectClient.go @@ -56,6 +56,19 @@ func (client *EasyConnectClient) AuthSMSCode(code string) ([]byte, error) { return client.LoginByTwfId(twfId) } +func (client *EasyConnectClient) AuthTOTP(code string) ([]byte, error) { + if client.twfId == "" { + return nil, errors.New("TOTP Auth not required") + } + + twfId, err := TOTPAuth(client.server, client.username, client.password, client.twfId, code) + if err != nil { + return nil, err + } + + return client.LoginByTwfId(twfId) +} + func (client *EasyConnectClient) LoginByTwfId(twfId string) ([]byte, error) { agentToken, err := ECAgentToken(client.server, twfId) if err != nil { diff --git a/core/web_login.go b/core/web_login.go index 98f8afa..999c8d1 100644 --- a/core/web_login.go +++ b/core/web_login.go @@ -20,7 +20,8 @@ import ( utls "github.com/refraction-networking/utls" ) -var ERR_NEXT_AUTH_SMS = errors.New("SMS Code required.") +var ERR_NEXT_AUTH_SMS = errors.New("SMS Code required") +var ERR_NEXT_AUTH_TOTP = errors.New("Current user's TOTP bound") func WebLogin(server string, username string, password string) (string, error) { server = "https://" + server @@ -138,6 +139,12 @@ func WebLogin(server string, username string, password string) (string, error) { return twfId, ERR_NEXT_AUTH_SMS } + // TOTP Authnication Process (Edited by JHong) + if strings.Contains(string(buf[:n]), "auth/token") || strings.Contains(string(buf[:n]), "totp") { + log.Print("TOTP Authnication required.") + return twfId, ERR_NEXT_AUTH_TOTP + } + if strings.Contains(string(buf[:n]), "-1") || !strings.Contains(string(buf[:n]), "") { log.Print("No NextAuth found.") } else { @@ -198,6 +205,44 @@ func AuthSms(server string, username string, password string, twfId string, smsC return twfId, nil } +// JHong Implementing....... +func TOTPAuth(server string, username string, password string, twfId string, TOTPCode string) (string, error) { + c := &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, + }} + + buf := make([]byte, 40960) + + addr := "https://" + server + "/por/login_token.csp" + log.Printf("TOTP token Request: " + addr) + form := url.Values{ + "svpn_inputtoken": {TOTPCode}, + } + + req, err := http.NewRequest("POST", addr, strings.NewReader(form.Encode())) + req.Header.Set("Cookie", "TWFID="+twfId) + + resp, err := c.Do(req) + if err != nil { + debug.PrintStack() + return "", err + } + + n, _ := resp.Body.Read(buf) + defer resp.Body.Close() + + if !strings.Contains(string(buf[:n]), "suc") { + debug.PrintStack() + return "", errors.New("TOTP token verification FAILED: " + string(buf[:n])) + } + + twfId = string(regexp.MustCompile(`(.*)`).FindSubmatch(buf[:n])[1]) + log.Print("TOTP verification SUCCESS") + + return twfId, nil +} + func ECAgentToken(server string, twfId string) (string, error) { dialConn, err := net.Dial("tcp", server) defer dialConn.Close() diff --git a/main.go b/main.go index e9a76d3..fc5948d 100644 --- a/main.go +++ b/main.go @@ -11,7 +11,7 @@ import ( func main() { // CLI args host, port, username, password, socksBind, twfId := "", 0, "", "", "", "" - flag.StringVar(&host, "server", "", "EasyConnect server address (e.g. vpn.nju.edu.cn)") + flag.StringVar(&host, "server", "", "EasyConnect server address (e.g. vpn.nju.edu.cn, sslvpn.sysu.edu.cn)") flag.StringVar(&username, "username", "", "Your username") flag.StringVar(&password, "password", "", "Your password") flag.StringVar(&socksBind, "socks-bind", ":1080", "The addr socks5 server listens on (e.g. 0.0.0.0:1080)") @@ -43,6 +43,12 @@ func main() { fmt.Scan(&smsCode) ip, err = client.AuthSMSCode(smsCode) + } else if err == core.ERR_NEXT_AUTH_TOTP { + fmt.Print(">>>Please enter your TOTP Auth code<<<:") + TOTPCode := "" + fmt.Scan(&TOTPCode) + + ip, err = client.AuthTOTP(TOTPCode) } }