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 |
package commons |
||||||
|
|
||||||
import "runtime" |
import ( |
||||||
|
"runtime" |
||||||
|
"strconv" |
||||||
|
"time" |
||||||
|
) |
||||||
|
|
||||||
func IsWindows() bool { |
func IsWindows() bool { |
||||||
return runtime.GOOS == "windows" |
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