parent
c99bc55f4a
commit
9284cfc4ae
@ -0,0 +1,14 @@ |
||||
package codecs |
||||
|
||||
import ( |
||||
"crypto/hmac" |
||||
"crypto/md5" |
||||
"encoding/hex" |
||||
) |
||||
|
||||
func HmacMd5(key, data string) string { |
||||
h := hmac.New(md5.New, []byte(key)) |
||||
h.Write([]byte(data)) |
||||
|
||||
return hex.EncodeToString(h.Sum(nil)) |
||||
} |
@ -1,7 +1,31 @@ |
||||
package commons |
||||
|
||||
import "runtime" |
||||
import ( |
||||
"runtime" |
||||
"strconv" |
||||
"time" |
||||
) |
||||
|
||||
func IsWindows() bool { |
||||
return runtime.GOOS == "windows" |
||||
} |
||||
|
||||
func CurrentMilliSecond() string { |
||||
return strconv.FormatInt(time.Now().UnixMilli(), 10) |
||||
} |
||||
|
||||
func CurrentSecond() string { |
||||
return strconv.FormatInt(time.Now().Unix(), 10) |
||||
} |
||||
|
||||
func GetOsName() string { |
||||
if IsWindows() { |
||||
return GetOsType() + " NT" |
||||
} else { |
||||
return GetOsType() |
||||
} |
||||
} |
||||
|
||||
func GetOsType() string { |
||||
return runtime.GOOS |
||||
} |
||||
|
@ -0,0 +1,19 @@ |
||||
package commons |
||||
|
||||
import ( |
||||
"fmt" |
||||
"regexp" |
||||
) |
||||
|
||||
var jqueryJsonRegexp = regexp.MustCompile("\\d+\\((?P<json>.*?)\\)$") |
||||
|
||||
func FilterJQueryPrefix(source string) string { |
||||
result := jqueryJsonRegexp.FindStringSubmatch(source) |
||||
|
||||
if len(result) < 2 { |
||||
fmt.Errorf("jquery字段提纯失败,原字符串:", source) |
||||
return "" |
||||
} else { |
||||
return result[1] |
||||
} |
||||
} |
@ -0,0 +1,13 @@ |
||||
package error |
||||
|
||||
type NotNeedLogin struct{} |
||||
|
||||
func (receiver *NotNeedLogin) Error() string { |
||||
return "Network is available, needn't login." |
||||
} |
||||
|
||||
type PasswordWrongError struct{} |
||||
|
||||
func (receiver PasswordWrongError) Error() string { |
||||
return "The password is wrong." |
||||
} |
@ -0,0 +1,24 @@ |
||||
package model |
||||
|
||||
type ChallengeCodeResponse struct { |
||||
Challenge string `json:"challenge"` |
||||
|
||||
Error string `json:"error"` |
||||
ErrorMsg string `json:"error_msg"` |
||||
Res string `json:"res"` |
||||
SrunVer string `json:"srun_ver"` |
||||
St int `json:"st"` |
||||
} |
||||
|
||||
//{
|
||||
// "challenge": "3c6d08d667d0ee0ccad77c55b19d3e4ab2552f7163ec40a9389095a18f86c398",
|
||||
// "client_ip": "10.16.1.9",
|
||||
// "ecode": 0,
|
||||
// "error": "ok",
|
||||
// "error_msg": "",
|
||||
// "expire": "52",
|
||||
// "online_ip": "10.16.1.9",
|
||||
// "res": "ok",
|
||||
// "srun_ver": "SRunCGIAuthIntfSvr V1.18 B20211105",
|
||||
// "st": 1668219964
|
||||
//}
|
@ -0,0 +1,21 @@ |
||||
package network |
||||
|
||||
import ( |
||||
"canti/app/api" |
||||
"github.com/go-resty/resty/v2" |
||||
) |
||||
|
||||
const ( |
||||
TestBaidu = "http://baidu.com" |
||||
TestTencent = "http://qq.com" |
||||
TestTaobao = "http://taobao.com" |
||||
TestSchoolNetwork = api.Host |
||||
) |
||||
|
||||
// CheckNetwork 检查网络是否可通
|
||||
func CheckNetwork(testUrl string) bool { |
||||
client := resty.New() |
||||
resp, err := client.R().SetHeaders(defaultHeaders).Get(testUrl) |
||||
|
||||
return err != nil && resp.Body() != nil |
||||
} |
@ -0,0 +1,52 @@ |
||||
package network |
||||
|
||||
import ( |
||||
"canti/app/commons" |
||||
"strconv" |
||||
"time" |
||||
) |
||||
|
||||
type QueryParam map[string]string |
||||
|
||||
func (param QueryParam) Add(key string, value string) { |
||||
param[key] = value |
||||
} |
||||
|
||||
// generateCallback callback参数生成,虽然说实际上callback参数随意设置也行,但是还是生成一个类似的比较好
|
||||
func generateCallback() string { |
||||
return "jQuery_1124005588867363182781_" + strconv.FormatInt(time.Now().UnixMilli(), 10) |
||||
} |
||||
|
||||
func userInfoQuery() QueryParam { |
||||
return QueryParam{ |
||||
"callback": generateCallback(), |
||||
} |
||||
} |
||||
|
||||
func challengeCodeQuery(username string, ip string) QueryParam { |
||||
return QueryParam{ |
||||
"callback": generateCallback(), |
||||
"username": username, |
||||
"ip": ip, |
||||
"_": commons.CurrentMilliSecond(), |
||||
} |
||||
} |
||||
|
||||
func authQuery(username, password, checkSum, info, ip string) QueryParam { |
||||
return QueryParam{ |
||||
"callback": generateCallback(), |
||||
"action": "login", |
||||
"username": username, |
||||
"password": password, |
||||
"os": commons.GetOsType(), |
||||
"name": commons.GetOsName(), |
||||
"double_stack": "0", |
||||
"chksum": checkSum, |
||||
"info": info, |
||||
"ac_id": "7", |
||||
"ip": ip, |
||||
"n": "200", |
||||
"type": "1", |
||||
"_": commons.CurrentMilliSecond(), |
||||
} |
||||
} |
@ -0,0 +1,88 @@ |
||||
package network |
||||
|
||||
import ( |
||||
"canti/app/api" |
||||
"canti/app/codecs" |
||||
"canti/app/commons" |
||||
"canti/app/model" |
||||
"encoding/json" |
||||
"github.com/go-resty/resty/v2" |
||||
) |
||||
|
||||
var defaultHeaders = map[string]string{ |
||||
"Accept": "text/javascript, application/javascript, application/ecmascript, application/x-ecmascript, */*; q=0.01", |
||||
"Accept-Encoding": "gzip, deflate", |
||||
"Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6", |
||||
"Cache-Control": "no-cache", |
||||
"Connection": "keep-alive", |
||||
"Host": "59.68.177.183", |
||||
"Pragma": "", |
||||
"Referer": "http://59.68.177.183/srun_portal_pc?ac_id=7&theme=pro", |
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.42", |
||||
"X-Requested-With": "XMLHttpRequest", |
||||
} |
||||
|
||||
func sendGetRequest(url string, param QueryParam) (string, error) { |
||||
client := resty.New() |
||||
resp, err := client.R(). |
||||
SetQueryParams(param). |
||||
SetHeaders(defaultHeaders). |
||||
Get(url) |
||||
|
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
return commons.FilterJQueryPrefix(resp.String()), nil |
||||
} |
||||
|
||||
func RequestAuth(username, password, ip, challengeCode string) (string, error) { |
||||
md5Password := codecs.HmacMd5(challengeCode, password) |
||||
|
||||
jsonMap := infoBody{ |
||||
Username: username, |
||||
Password: password, |
||||
Ip: ip, |
||||
Acid: "7", |
||||
EncVer: "srun_bx1", |
||||
} |
||||
infoData, _ := json.Marshal(jsonMap) |
||||
info := string(infoData) |
||||
|
||||
encodedInfo := `{SRBX1}` + codecs.SRBX1Encode(info, challengeCode) |
||||
|
||||
checksum := codecs.Checksum(challengeCode, username, md5Password, ip, encodedInfo) |
||||
|
||||
return sendGetRequest(api.AuthApi, authQuery(username, `{md5}`+md5Password, checksum, encodedInfo, ip)) |
||||
} |
||||
|
||||
type infoBody struct { |
||||
Username string `json:"username"` |
||||
Password string `json:"password"` |
||||
Ip string `json:"ip"` |
||||
Acid string `json:"acid"` |
||||
EncVer string `json:"enc_ver"` |
||||
} |
||||
|
||||
func RequestChallengeCode(username, ip string) (string, error) { |
||||
return sendGetRequest(api.ChallengeCodeApi, challengeCodeQuery(username, ip)) |
||||
} |
||||
|
||||
func RequestUserInfo() (string, error) { |
||||
return sendGetRequest(api.UserInfoApi, userInfoQuery()) |
||||
} |
||||
|
||||
func GetClientIp() (ip string, errs error) { |
||||
userInfoJson, err := RequestUserInfo() |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
var userInfo model.UserInfo |
||||
err2 := json.Unmarshal([]byte(userInfoJson), &userInfo) |
||||
if err2 != nil { |
||||
return "", err2 |
||||
} |
||||
|
||||
return userInfo.OnlineIp, nil |
||||
} |
@ -0,0 +1,14 @@ |
||||
package network |
||||
|
||||
type ChallengeCodeResponse struct { |
||||
Challenge string `json:"challenge"` |
||||
ClientIp string `json:"client_ip"` |
||||
Ecode int `json:"ecode"` |
||||
Error string `json:"error"` |
||||
ErrorMsg string `json:"error_msg"` |
||||
Expire string `json:"expire"` |
||||
OnlineIp string `json:"online_ip"` |
||||
Res string `json:"res"` |
||||
SrunVer string `json:"srun_ver"` |
||||
St int `json:"st"` |
||||
} |
@ -0,0 +1,46 @@ |
||||
package service |
||||
|
||||
import ( |
||||
"canti/app/model" |
||||
"canti/app/network" |
||||
"encoding/json" |
||||
"errors" |
||||
"fmt" |
||||
) |
||||
|
||||
var NoNeedLogin = errors.New("no need to login") |
||||
var UserinfoError = errors.New("error happens in requesting userinfo") |
||||
var ChallengeCodeError = errors.New("error happens in requesting challenge code") |
||||
|
||||
func WebLogin(username string, password string) error { |
||||
// 能直接上网的话就不用登陆了
|
||||
if network.CheckNetwork(network.TestBaidu) { |
||||
return NoNeedLogin |
||||
} |
||||
|
||||
ip, err := network.GetClientIp() |
||||
if err != nil || ip == "" || ip == "<nil>" { |
||||
return UserinfoError |
||||
} |
||||
|
||||
fmt.Print("Got ip:") |
||||
fmt.Println(ip) |
||||
|
||||
challengeCodeJson, err2 := network.RequestChallengeCode(username, ip) |
||||
if err2 != nil || challengeCodeJson == "" { |
||||
return err |
||||
} |
||||
|
||||
var challengeCodeResponse model.ChallengeCodeResponse |
||||
jsonError := json.Unmarshal([]byte(challengeCodeJson), &challengeCodeResponse) |
||||
if jsonError != nil { |
||||
return jsonError |
||||
} else if challengeCodeResponse.Challenge == "" { |
||||
_ = fmt.Errorf(challengeCodeJson) |
||||
return ChallengeCodeError |
||||
} |
||||
|
||||
fmt.Print(challengeCodeResponse) |
||||
|
||||
return nil |
||||
} |
@ -0,0 +1,8 @@ |
||||
{ |
||||
"username": "202100000000", |
||||
"password": "password12450", |
||||
"method": "web", |
||||
"max-retry-times": 3, |
||||
"keep-alive": false, |
||||
"reconnect": true |
||||
} |
@ -0,0 +1,7 @@ |
||||
canti: |
||||
username: "202100000000" |
||||
password: "password12450" |
||||
method: "web" |
||||
max-retry-times: 3 |
||||
keep-alive: false |
||||
reconnect: true |
Loading…
Reference in new issue