-
Notifications
You must be signed in to change notification settings - Fork 2
/
handler.go
129 lines (109 loc) · 2.94 KB
/
handler.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
package neugo
import (
"errors"
"net/http"
"regexp"
"strconv"
"strings"
)
var (
// generated from EncryptURLToWebVPN("https://pass.neu.edu.cn/tpass/login")
webvpnLoginURL = "https://webvpn.neu.edu.cn/https/77726476706e69737468656265737421e0f6528f693e6d45300d8db9d6562d/tpass/login"
casLoginURL = "https://pass.neu.edu.cn/tpass/login"
webvpnCookieDomain = ".webvpn.neu.edu.cn"
casCookieDomain = "pass.neu.edu.cn"
)
// Perform login request and returns the body of response.
//
// If login failed, an error will be returned with the body.
func login(c config) (string, error) {
var resp *http.Response
var err error
var loginURL string
var request *http.Request
if c.Platform == CAS {
loginURL = casLoginURL
} else {
loginURL = webvpnLoginURL
}
if c.UseToken {
setToken(c.Client, c.Token, c.Platform)
request = buildGetRequest(loginURL)
} else {
lt, err := getLT(c.Client, loginURL)
if err != nil {
return "", err
}
request = buildAuthRequest(c.Username, c.Password, lt, loginURL)
}
resp, err = c.Client.Do(request)
if err != nil {
return "", err
}
body := extractBody(resp)
_, err = isLogged(body)
return body, err
}
var (
ltExp = regexp.MustCompile(`name="lt" value="(.+?)"`)
ErrorLTNotFound = errors.New("LT not found")
)
// Get LT by performing a pre-request.
func getLT(client *http.Client, requestURL string) (string, error) {
req := buildGetRequest(requestURL)
resp, err := client.Do(req)
if err != nil {
return "", err
}
body := extractBody(resp)
lt := matchSingle(ltExp, body)
if lt == "" {
return "", ErrorLTNotFound
}
return lt, nil
}
// Build a POST *http.Request for login.
func buildAuthRequest(username, password, lt, reqURL string) (req *http.Request) {
data := "rsa=" + username + password + lt +
"&ul=" + strconv.Itoa(len(username)) +
"&pl=" + strconv.Itoa(len(password)) +
"<=" + lt +
"&execution=e1s1" +
"&_eventId=submit"
req, _ = http.NewRequest("POST",
reqURL,
strings.NewReader(data))
req.Header.Add("Content-Type", "application/x-www-form-urlencoded")
req.Header.Add("Referer", reqURL)
return
}
// Build a GET *http.Request.
func buildGetRequest(reqURL string) (req *http.Request) {
req, _ = http.NewRequest("GET", reqURL, nil)
return
}
var (
titleExp = regexp.MustCompile(`<title>(.+?)</title>`)
)
var (
ErrorAccountBanned = errors.New("account is banned")
ErrorAccountNeedsReset = errors.New("account needs reset")
ErrorAuthFailed = errors.New("incorrect username or password or cookie")
)
// Check if logged in successfully.
func isLogged(body string) (bool, error) {
// FIXME: use better verification methods instead of comparing titles
title := matchSingle(titleExp, body)
if title == "" {
return true, nil
}
switch title {
case "智慧东大--统一身份认证":
return false, ErrorAuthFailed
case "智慧东大":
return false, ErrorAccountNeedsReset
case "系统提示":
return false, ErrorAccountBanned
}
return true, nil
}