Skip to content

Commit 6ac7a8f

Browse files
authored
Merge pull request #2470 from Mrs4s/dev
chore: sync dev to master
2 parents 642c746 + bd785d3 commit 6ac7a8f

File tree

13 files changed

+658
-487
lines changed

13 files changed

+658
-487
lines changed

cmd/gocq/login.go

Lines changed: 0 additions & 284 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,21 @@ package gocq
33
import (
44
"bufio"
55
"bytes"
6-
"encoding/hex"
76
"fmt"
87
"image"
98
"image/png"
10-
"net/http"
11-
"net/url"
129
"os"
13-
"strconv"
1410
"strings"
15-
"sync"
16-
"sync/atomic"
1711
"time"
1812

1913
"github.com/Mrs4s/MiraiGo/client"
2014
"github.com/Mrs4s/MiraiGo/utils"
2115
"github.com/mattn/go-colorable"
2216
"github.com/pkg/errors"
2317
log "github.com/sirupsen/logrus"
24-
"github.com/tidwall/gjson"
2518
"gopkg.ilharper.com/x/isatty"
2619

2720
"github.com/Mrs4s/go-cqhttp/global"
28-
"github.com/Mrs4s/go-cqhttp/internal/base"
2921
"github.com/Mrs4s/go-cqhttp/internal/download"
3022
)
3123

@@ -268,279 +260,3 @@ func fetchCaptcha(id string) string {
268260
}
269261
return ""
270262
}
271-
272-
func energy(uin uint64, id string, _ string, salt []byte) ([]byte, error) {
273-
signServer := base.SignServer
274-
if !strings.HasSuffix(signServer, "/") {
275-
signServer += "/"
276-
}
277-
headers := make(map[string]string)
278-
signServerBearer := base.SignServerBearer
279-
if signServerBearer != "-" && signServerBearer != "" {
280-
headers["Authorization"] = "Bearer " + signServerBearer
281-
}
282-
req := download.Request{
283-
Method: http.MethodGet,
284-
Header: headers,
285-
URL: signServer + "custom_energy" + fmt.Sprintf("?data=%v&salt=%v&uin=%v&android_id=%v&guid=%v",
286-
id, hex.EncodeToString(salt), uin, utils.B2S(device.AndroidId), hex.EncodeToString(device.Guid)),
287-
}.WithTimeout(time.Duration(base.SignServerTimeout) * time.Second)
288-
if base.IsBelow110 {
289-
req.URL = signServer + "custom_energy" + fmt.Sprintf("?data=%v&salt=%v", id, hex.EncodeToString(salt))
290-
}
291-
response, err := req.Bytes()
292-
if err != nil {
293-
log.Warnf("获取T544 sign时出现错误: %v server: %v", err, signServer)
294-
return nil, err
295-
}
296-
data, err := hex.DecodeString(gjson.GetBytes(response, "data").String())
297-
if err != nil {
298-
log.Warnf("获取T544 sign时出现错误: %v", err)
299-
return nil, err
300-
}
301-
if len(data) == 0 {
302-
log.Warnf("获取T544 sign时出现错误: %v", "data is empty")
303-
return nil, errors.New("data is empty")
304-
}
305-
return data, nil
306-
}
307-
308-
// signSubmit 提交的操作类型
309-
func signSubmit(uin string, cmd string, callbackID int64, buffer []byte, t string) {
310-
signServer := base.SignServer
311-
if !strings.HasSuffix(signServer, "/") {
312-
signServer += "/"
313-
}
314-
buffStr := hex.EncodeToString(buffer)
315-
log.Infof("submit %v: uin=%v, cmd=%v, callbackID=%v, buffer-end=%v", t, uin, cmd, callbackID,
316-
buffStr[len(buffStr)-10:])
317-
_, err := download.Request{
318-
Method: http.MethodGet,
319-
URL: signServer + "submit" + fmt.Sprintf("?uin=%v&cmd=%v&callback_id=%v&buffer=%v",
320-
uin, cmd, callbackID, buffStr),
321-
}.WithTimeout(time.Duration(base.SignServerTimeout) * time.Second).Bytes()
322-
if err != nil {
323-
log.Warnf("提交 callback 时出现错误: %v server: %v", err, signServer)
324-
}
325-
}
326-
327-
// signCallback request token 和签名的回调
328-
func signCallback(uin string, results []gjson.Result, t string) {
329-
for _, result := range results {
330-
cmd := result.Get("cmd").String()
331-
callbackID := result.Get("callbackId").Int()
332-
body, _ := hex.DecodeString(result.Get("body").String())
333-
ret, err := cli.SendSsoPacket(cmd, body)
334-
if err != nil {
335-
log.Warnf("callback error: %v", err)
336-
}
337-
signSubmit(uin, cmd, callbackID, ret, t)
338-
}
339-
}
340-
341-
func signRequset(seq uint64, uin string, cmd string, qua string, buff []byte) (sign []byte, extra []byte, token []byte, err error) {
342-
signServer := base.SignServer
343-
if !strings.HasSuffix(signServer, "/") {
344-
signServer += "/"
345-
}
346-
headers := map[string]string{"Content-Type": "application/x-www-form-urlencoded"}
347-
signServerBearer := base.SignServerBearer
348-
if signServerBearer != "-" && signServerBearer != "" {
349-
headers["Authorization"] = "Bearer " + signServerBearer
350-
}
351-
response, err := download.Request{
352-
Method: http.MethodPost,
353-
URL: signServer + "sign",
354-
Header: headers,
355-
Body: bytes.NewReader([]byte(fmt.Sprintf("uin=%v&qua=%s&cmd=%s&seq=%v&buffer=%v&android_id=%v&guid=%v",
356-
uin, qua, cmd, seq, hex.EncodeToString(buff), utils.B2S(device.AndroidId), hex.EncodeToString(device.Guid)))),
357-
}.WithTimeout(time.Duration(base.SignServerTimeout) * time.Second).Bytes()
358-
if err != nil {
359-
return nil, nil, nil, err
360-
}
361-
sign, _ = hex.DecodeString(gjson.GetBytes(response, "data.sign").String())
362-
extra, _ = hex.DecodeString(gjson.GetBytes(response, "data.extra").String())
363-
token, _ = hex.DecodeString(gjson.GetBytes(response, "data.token").String())
364-
if !base.IsBelow110 {
365-
go signCallback(uin, gjson.GetBytes(response, "data.requestCallback").Array(), "sign")
366-
}
367-
return sign, extra, token, nil
368-
}
369-
370-
var registerLock sync.Mutex
371-
372-
func signRegister(uin int64, androidID, guid []byte, qimei36, key string) {
373-
if base.IsBelow110 {
374-
log.Warn("签名服务器版本低于1.1.0, 跳过实例注册")
375-
return
376-
}
377-
signServer := base.SignServer
378-
if !strings.HasSuffix(signServer, "/") {
379-
signServer += "/"
380-
}
381-
resp, err := download.Request{
382-
Method: http.MethodGet,
383-
URL: signServer + "register" + fmt.Sprintf("?uin=%v&android_id=%v&guid=%v&qimei36=%v&key=%s",
384-
uin, utils.B2S(androidID), hex.EncodeToString(guid), qimei36, key),
385-
}.WithTimeout(time.Duration(base.SignServerTimeout) * time.Second).Bytes()
386-
if err != nil {
387-
log.Warnf("注册QQ实例时出现错误: %v server: %v", err, signServer)
388-
return
389-
}
390-
msg := gjson.GetBytes(resp, "msg")
391-
if gjson.GetBytes(resp, "code").Int() != 0 {
392-
log.Warnf("注册QQ实例时出现错误: %v server: %v", msg, signServer)
393-
return
394-
}
395-
log.Infof("注册QQ实例 %v 成功: %v", uin, msg)
396-
}
397-
398-
func signRefreshToken(uin string) error {
399-
signServer := base.SignServer
400-
if !strings.HasSuffix(signServer, "/") {
401-
signServer += "/"
402-
}
403-
log.Info("正在刷新 token")
404-
resp, err := download.Request{
405-
Method: http.MethodGet,
406-
URL: signServer + "request_token" + fmt.Sprintf("?uin=%v", uin),
407-
}.WithTimeout(time.Duration(base.SignServerTimeout) * time.Second).Bytes()
408-
if err != nil {
409-
return err
410-
}
411-
msg := gjson.GetBytes(resp, "msg")
412-
if gjson.GetBytes(resp, "code").Int() != 0 {
413-
return errors.New(msg.String())
414-
}
415-
go signCallback(uin, gjson.GetBytes(resp, "data").Array(), "request token")
416-
return nil
417-
}
418-
419-
var missTokenCount = uint64(0)
420-
421-
func sign(seq uint64, uin string, cmd string, qua string, buff []byte) (sign []byte, extra []byte, token []byte, err error) {
422-
i := 0
423-
for {
424-
sign, extra, token, err = signRequset(seq, uin, cmd, qua, buff)
425-
if err != nil {
426-
log.Warnf("获取sso sign时出现错误: %v server: %v", err, base.SignServer)
427-
}
428-
if i > 0 {
429-
break
430-
}
431-
i++
432-
if (!base.IsBelow110) && base.Account.AutoRegister && err == nil && len(sign) == 0 {
433-
if registerLock.TryLock() { // 避免并发时多处同时销毁并重新注册
434-
log.Warn("获取签名为空,实例可能丢失,正在尝试重新注册")
435-
defer registerLock.Unlock()
436-
err := signServerDestroy(uin)
437-
if err != nil {
438-
log.Warnln(err)
439-
return nil, nil, nil, err
440-
}
441-
signRegister(base.Account.Uin, device.AndroidId, device.Guid, device.QImei36, base.Key)
442-
}
443-
continue
444-
}
445-
if (!base.IsBelow110) && base.Account.AutoRefreshToken && len(token) == 0 {
446-
log.Warnf("token 已过期, 总丢失 token 次数为 %v", atomic.AddUint64(&missTokenCount, 1))
447-
if registerLock.TryLock() {
448-
defer registerLock.Unlock()
449-
if err := signRefreshToken(uin); err != nil {
450-
log.Warnf("刷新 token 出现错误: %v server: %v", err, base.SignServer)
451-
} else {
452-
log.Info("刷新 token 成功")
453-
}
454-
}
455-
continue
456-
}
457-
break
458-
}
459-
return sign, extra, token, err
460-
}
461-
462-
func signServerDestroy(uin string) error {
463-
signServer := base.SignServer
464-
if !strings.HasSuffix(signServer, "/") {
465-
signServer += "/"
466-
}
467-
signVersion, err := signVersion()
468-
if err != nil {
469-
return errors.Wrapf(err, "获取签名服务版本出现错误, server: %v", signServer)
470-
}
471-
if global.VersionNameCompare("v"+signVersion, "v1.1.6") {
472-
return errors.Errorf("当前签名服务器版本 %v 低于 1.1.6,无法使用 destroy 接口", signVersion)
473-
}
474-
resp, err := download.Request{
475-
Method: http.MethodGet,
476-
URL: signServer + "destroy" + fmt.Sprintf("?uin=%v&key=%v", uin, base.Key),
477-
}.WithTimeout(time.Duration(base.SignServerTimeout) * time.Second).Bytes()
478-
if err != nil || gjson.GetBytes(resp, "code").Int() != 0 {
479-
return errors.Wrapf(err, "destroy 实例出现错误, server: %v", signServer)
480-
}
481-
return nil
482-
}
483-
484-
func signVersion() (version string, err error) {
485-
signServer := base.SignServer
486-
resp, err := download.Request{
487-
Method: http.MethodGet,
488-
URL: signServer,
489-
}.WithTimeout(time.Duration(base.SignServerTimeout) * time.Second).Bytes()
490-
if err != nil {
491-
return "", err
492-
}
493-
if gjson.GetBytes(resp, "code").Int() == 0 {
494-
return gjson.GetBytes(resp, "data.version").String(), nil
495-
}
496-
return "", errors.New("empty version")
497-
}
498-
499-
// 定时刷新 token, interval 为间隔时间(分钟)
500-
func signStartRefreshToken(interval int64) {
501-
if interval <= 0 {
502-
log.Warn("定时刷新 token 已关闭")
503-
return
504-
}
505-
log.Infof("每 %v 分钟将刷新一次签名 token", interval)
506-
if interval < 10 {
507-
log.Warnf("间隔时间 %v 分钟较短,推荐 30~40 分钟", interval)
508-
}
509-
if interval > 60 {
510-
log.Warn("间隔时间不能超过 60 分钟,已自动设置为 60 分钟")
511-
interval = 60
512-
}
513-
t := time.NewTicker(time.Duration(interval) * time.Minute)
514-
defer t.Stop()
515-
for range t.C {
516-
err := signRefreshToken(strconv.FormatInt(base.Account.Uin, 10))
517-
if err != nil {
518-
log.Warnf("刷新 token 出现错误: %v server: %v", err, base.SignServer)
519-
}
520-
}
521-
}
522-
523-
func signWaitServer() bool {
524-
t := time.NewTicker(time.Second * 5)
525-
defer t.Stop()
526-
i := 0
527-
for range t.C {
528-
if i > 3 {
529-
return false
530-
}
531-
i++
532-
u, err := url.Parse(base.SignServer)
533-
if err != nil {
534-
log.Warnf("连接到签名服务器出现错误: %v", err)
535-
continue
536-
}
537-
r := utils.RunTCPPingLoop(u.Host, 4)
538-
if r.PacketsLoss > 0 {
539-
log.Warnf("连接到签名服务器出现错误: 丢包%d/%d 时延%dms", r.PacketsLoss, r.PacketsSent, r.AvgTimeMill)
540-
continue
541-
}
542-
break
543-
}
544-
log.Infof("连接至签名服务器: %s", base.SignServer)
545-
return true
546-
}

cmd/gocq/main.go

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -163,32 +163,27 @@ func LoginInteract() {
163163
log.Fatalf("加载设备信息失败: %v", err)
164164
}
165165
}
166-
167-
if base.SignServer != "-" && base.SignServer != "" {
168-
log.Infof("使用服务器 %s 进行数据包签名", base.SignServer)
169-
if base.SignServerBearer != "-" && base.SignServerBearer != "" {
170-
log.Infof("使用 Bearer %s 认证签名服务器 %s ", base.SignServerBearer, base.SignServer)
171-
}
172-
// 等待签名服务器直到连接成功
173-
if !signWaitServer() {
174-
log.Fatalf("连接签名服务器失败")
175-
}
176-
signRegister(base.Account.Uin, device.AndroidId, device.Guid, device.QImei36, base.Key)
166+
signServer, err := getAvaliableSignServer() // 获取可用签名服务器
167+
if err != nil {
168+
log.Warn(err)
169+
}
170+
if signServer != nil && len(signServer.URL) > 1 {
171+
log.Infof("使用签名服务器:%v", signServer.URL)
177172
go signStartRefreshToken(base.Account.RefreshInterval) // 定时刷新 token
178173
wrapper.DandelionEnergy = energy
179174
wrapper.FekitGetSign = sign
180175
if !base.IsBelow110 {
181176
if !base.Account.AutoRegister {
182-
log.Warn("自动注册实例已关闭,若未配置 sign-server 端自动注册实例则实例丢失时需要重启 go-cqhttp 以正常签名")
177+
log.Warn("自动注册实例已关闭,请配置 sign-server 端自动注册实例以保持正常签名")
183178
}
184179
if !base.Account.AutoRefreshToken {
185-
log.Warn("自动刷新 token 已关闭,token 过期后获取签名时将不会立即尝试刷新获取新 token")
180+
log.Info("自动刷新 token 已关闭,token 过期后获取签名时将不会立即尝试刷新获取新 token")
186181
}
187182
} else {
188183
log.Warn("签名服务器版本 <= 1.1.0 ,无法使用刷新 token 等操作,建议使用 1.1.6 版本及以上签名服务器")
189184
}
190185
} else {
191-
log.Warnf("警告: 未配置签名服务器, 这可能会导致登录 45 错误码或发送消息被风控")
186+
log.Warnf("警告: 未配置签名服务器或签名服务器不可用, 这可能会导致登录 45 错误码或发送消息被风控")
192187
}
193188

194189
if base.Account.Encrypt {

0 commit comments

Comments
 (0)