diff --git a/README.md b/README.md index 8efa36cbb..2816097b0 100644 --- a/README.md +++ b/README.md @@ -42,6 +42,9 @@ _✨ 基于 [Mirai](https://github.com/mamoe/mirai) 以及 [MiraiGo](https://git 参与贡献

+## 重要信息 +由于QQ官方针对协议库的围追堵截, 不断更新加密方案, 我们已无力继续维护此项目. +建议Bot开发者尽快迁移至无头NTQQ项目 -> https://github.com/Mrs4s/go-cqhttp/issues/2471 ## 兼容性 go-cqhttp 兼容 [OneBot-v11](https://github.com/botuniverse/onebot-11) 绝大多数内容,并在其基础上做了一些扩展,详情请看 go-cqhttp 的文档。 diff --git a/cmd/gocq/login.go b/cmd/gocq/login.go index 0bc2d7a0b..4feab4f78 100644 --- a/cmd/gocq/login.go +++ b/cmd/gocq/login.go @@ -3,17 +3,11 @@ package gocq import ( "bufio" "bytes" - "encoding/hex" "fmt" "image" "image/png" - "net/http" - "net/url" "os" - "strconv" "strings" - "sync" - "sync/atomic" "time" "github.com/Mrs4s/MiraiGo/client" @@ -21,11 +15,9 @@ import ( "github.com/mattn/go-colorable" "github.com/pkg/errors" log "github.com/sirupsen/logrus" - "github.com/tidwall/gjson" "gopkg.ilharper.com/x/isatty" "github.com/Mrs4s/go-cqhttp/global" - "github.com/Mrs4s/go-cqhttp/internal/base" "github.com/Mrs4s/go-cqhttp/internal/download" ) @@ -268,279 +260,3 @@ func fetchCaptcha(id string) string { } return "" } - -func energy(uin uint64, id string, _ string, salt []byte) ([]byte, error) { - signServer := base.SignServer - if !strings.HasSuffix(signServer, "/") { - signServer += "/" - } - headers := make(map[string]string) - signServerBearer := base.SignServerBearer - if signServerBearer != "-" && signServerBearer != "" { - headers["Authorization"] = "Bearer " + signServerBearer - } - req := download.Request{ - Method: http.MethodGet, - Header: headers, - URL: signServer + "custom_energy" + fmt.Sprintf("?data=%v&salt=%v&uin=%v&android_id=%v&guid=%v", - id, hex.EncodeToString(salt), uin, utils.B2S(device.AndroidId), hex.EncodeToString(device.Guid)), - }.WithTimeout(time.Duration(base.SignServerTimeout) * time.Second) - if base.IsBelow110 { - req.URL = signServer + "custom_energy" + fmt.Sprintf("?data=%v&salt=%v", id, hex.EncodeToString(salt)) - } - response, err := req.Bytes() - if err != nil { - log.Warnf("获取T544 sign时出现错误: %v server: %v", err, signServer) - return nil, err - } - data, err := hex.DecodeString(gjson.GetBytes(response, "data").String()) - if err != nil { - log.Warnf("获取T544 sign时出现错误: %v", err) - return nil, err - } - if len(data) == 0 { - log.Warnf("获取T544 sign时出现错误: %v", "data is empty") - return nil, errors.New("data is empty") - } - return data, nil -} - -// signSubmit 提交的操作类型 -func signSubmit(uin string, cmd string, callbackID int64, buffer []byte, t string) { - signServer := base.SignServer - if !strings.HasSuffix(signServer, "/") { - signServer += "/" - } - buffStr := hex.EncodeToString(buffer) - log.Infof("submit %v: uin=%v, cmd=%v, callbackID=%v, buffer-end=%v", t, uin, cmd, callbackID, - buffStr[len(buffStr)-10:]) - _, err := download.Request{ - Method: http.MethodGet, - URL: signServer + "submit" + fmt.Sprintf("?uin=%v&cmd=%v&callback_id=%v&buffer=%v", - uin, cmd, callbackID, buffStr), - }.WithTimeout(time.Duration(base.SignServerTimeout) * time.Second).Bytes() - if err != nil { - log.Warnf("提交 callback 时出现错误: %v server: %v", err, signServer) - } -} - -// signCallback request token 和签名的回调 -func signCallback(uin string, results []gjson.Result, t string) { - for _, result := range results { - cmd := result.Get("cmd").String() - callbackID := result.Get("callbackId").Int() - body, _ := hex.DecodeString(result.Get("body").String()) - ret, err := cli.SendSsoPacket(cmd, body) - if err != nil { - log.Warnf("callback error: %v", err) - } - signSubmit(uin, cmd, callbackID, ret, t) - } -} - -func signRequset(seq uint64, uin string, cmd string, qua string, buff []byte) (sign []byte, extra []byte, token []byte, err error) { - signServer := base.SignServer - if !strings.HasSuffix(signServer, "/") { - signServer += "/" - } - headers := map[string]string{"Content-Type": "application/x-www-form-urlencoded"} - signServerBearer := base.SignServerBearer - if signServerBearer != "-" && signServerBearer != "" { - headers["Authorization"] = "Bearer " + signServerBearer - } - response, err := download.Request{ - Method: http.MethodPost, - URL: signServer + "sign", - Header: headers, - Body: bytes.NewReader([]byte(fmt.Sprintf("uin=%v&qua=%s&cmd=%s&seq=%v&buffer=%v&android_id=%v&guid=%v", - uin, qua, cmd, seq, hex.EncodeToString(buff), utils.B2S(device.AndroidId), hex.EncodeToString(device.Guid)))), - }.WithTimeout(time.Duration(base.SignServerTimeout) * time.Second).Bytes() - if err != nil { - return nil, nil, nil, err - } - sign, _ = hex.DecodeString(gjson.GetBytes(response, "data.sign").String()) - extra, _ = hex.DecodeString(gjson.GetBytes(response, "data.extra").String()) - token, _ = hex.DecodeString(gjson.GetBytes(response, "data.token").String()) - if !base.IsBelow110 { - go signCallback(uin, gjson.GetBytes(response, "data.requestCallback").Array(), "sign") - } - return sign, extra, token, nil -} - -var registerLock sync.Mutex - -func signRegister(uin int64, androidID, guid []byte, qimei36, key string) { - if base.IsBelow110 { - log.Warn("签名服务器版本低于1.1.0, 跳过实例注册") - return - } - signServer := base.SignServer - if !strings.HasSuffix(signServer, "/") { - signServer += "/" - } - resp, err := download.Request{ - Method: http.MethodGet, - URL: signServer + "register" + fmt.Sprintf("?uin=%v&android_id=%v&guid=%v&qimei36=%v&key=%s", - uin, utils.B2S(androidID), hex.EncodeToString(guid), qimei36, key), - }.WithTimeout(time.Duration(base.SignServerTimeout) * time.Second).Bytes() - if err != nil { - log.Warnf("注册QQ实例时出现错误: %v server: %v", err, signServer) - return - } - msg := gjson.GetBytes(resp, "msg") - if gjson.GetBytes(resp, "code").Int() != 0 { - log.Warnf("注册QQ实例时出现错误: %v server: %v", msg, signServer) - return - } - log.Infof("注册QQ实例 %v 成功: %v", uin, msg) -} - -func signRefreshToken(uin string) error { - signServer := base.SignServer - if !strings.HasSuffix(signServer, "/") { - signServer += "/" - } - log.Info("正在刷新 token") - resp, err := download.Request{ - Method: http.MethodGet, - URL: signServer + "request_token" + fmt.Sprintf("?uin=%v", uin), - }.WithTimeout(time.Duration(base.SignServerTimeout) * time.Second).Bytes() - if err != nil { - return err - } - msg := gjson.GetBytes(resp, "msg") - if gjson.GetBytes(resp, "code").Int() != 0 { - return errors.New(msg.String()) - } - go signCallback(uin, gjson.GetBytes(resp, "data").Array(), "request token") - return nil -} - -var missTokenCount = uint64(0) - -func sign(seq uint64, uin string, cmd string, qua string, buff []byte) (sign []byte, extra []byte, token []byte, err error) { - i := 0 - for { - sign, extra, token, err = signRequset(seq, uin, cmd, qua, buff) - if err != nil { - log.Warnf("获取sso sign时出现错误: %v server: %v", err, base.SignServer) - } - if i > 0 { - break - } - i++ - if (!base.IsBelow110) && base.Account.AutoRegister && err == nil && len(sign) == 0 { - if registerLock.TryLock() { // 避免并发时多处同时销毁并重新注册 - log.Warn("获取签名为空,实例可能丢失,正在尝试重新注册") - defer registerLock.Unlock() - err := signServerDestroy(uin) - if err != nil { - log.Warnln(err) - return nil, nil, nil, err - } - signRegister(base.Account.Uin, device.AndroidId, device.Guid, device.QImei36, base.Key) - } - continue - } - if (!base.IsBelow110) && base.Account.AutoRefreshToken && len(token) == 0 { - log.Warnf("token 已过期, 总丢失 token 次数为 %v", atomic.AddUint64(&missTokenCount, 1)) - if registerLock.TryLock() { - defer registerLock.Unlock() - if err := signRefreshToken(uin); err != nil { - log.Warnf("刷新 token 出现错误: %v server: %v", err, base.SignServer) - } else { - log.Info("刷新 token 成功") - } - } - continue - } - break - } - return sign, extra, token, err -} - -func signServerDestroy(uin string) error { - signServer := base.SignServer - if !strings.HasSuffix(signServer, "/") { - signServer += "/" - } - signVersion, err := signVersion() - if err != nil { - return errors.Wrapf(err, "获取签名服务版本出现错误, server: %v", signServer) - } - if global.VersionNameCompare("v"+signVersion, "v1.1.6") { - return errors.Errorf("当前签名服务器版本 %v 低于 1.1.6,无法使用 destroy 接口", signVersion) - } - resp, err := download.Request{ - Method: http.MethodGet, - URL: signServer + "destroy" + fmt.Sprintf("?uin=%v&key=%v", uin, base.Key), - }.WithTimeout(time.Duration(base.SignServerTimeout) * time.Second).Bytes() - if err != nil || gjson.GetBytes(resp, "code").Int() != 0 { - return errors.Wrapf(err, "destroy 实例出现错误, server: %v", signServer) - } - return nil -} - -func signVersion() (version string, err error) { - signServer := base.SignServer - resp, err := download.Request{ - Method: http.MethodGet, - URL: signServer, - }.WithTimeout(time.Duration(base.SignServerTimeout) * time.Second).Bytes() - if err != nil { - return "", err - } - if gjson.GetBytes(resp, "code").Int() == 0 { - return gjson.GetBytes(resp, "data.version").String(), nil - } - return "", errors.New("empty version") -} - -// 定时刷新 token, interval 为间隔时间(分钟) -func signStartRefreshToken(interval int64) { - if interval <= 0 { - log.Warn("定时刷新 token 已关闭") - return - } - log.Infof("每 %v 分钟将刷新一次签名 token", interval) - if interval < 10 { - log.Warnf("间隔时间 %v 分钟较短,推荐 30~40 分钟", interval) - } - if interval > 60 { - log.Warn("间隔时间不能超过 60 分钟,已自动设置为 60 分钟") - interval = 60 - } - t := time.NewTicker(time.Duration(interval) * time.Minute) - defer t.Stop() - for range t.C { - err := signRefreshToken(strconv.FormatInt(base.Account.Uin, 10)) - if err != nil { - log.Warnf("刷新 token 出现错误: %v server: %v", err, base.SignServer) - } - } -} - -func signWaitServer() bool { - t := time.NewTicker(time.Second * 5) - defer t.Stop() - i := 0 - for range t.C { - if i > 3 { - return false - } - i++ - u, err := url.Parse(base.SignServer) - if err != nil { - log.Warnf("连接到签名服务器出现错误: %v", err) - continue - } - r := utils.RunTCPPingLoop(u.Host, 4) - if r.PacketsLoss > 0 { - log.Warnf("连接到签名服务器出现错误: 丢包%d/%d 时延%dms", r.PacketsLoss, r.PacketsSent, r.AvgTimeMill) - continue - } - break - } - log.Infof("连接至签名服务器: %s", base.SignServer) - return true -} diff --git a/cmd/gocq/main.go b/cmd/gocq/main.go index 4e71431e8..fe0b04066 100644 --- a/cmd/gocq/main.go +++ b/cmd/gocq/main.go @@ -163,32 +163,27 @@ func LoginInteract() { log.Fatalf("加载设备信息失败: %v", err) } } - - if base.SignServer != "-" && base.SignServer != "" { - log.Infof("使用服务器 %s 进行数据包签名", base.SignServer) - if base.SignServerBearer != "-" && base.SignServerBearer != "" { - log.Infof("使用 Bearer %s 认证签名服务器 %s ", base.SignServerBearer, base.SignServer) - } - // 等待签名服务器直到连接成功 - if !signWaitServer() { - log.Fatalf("连接签名服务器失败") - } - signRegister(base.Account.Uin, device.AndroidId, device.Guid, device.QImei36, base.Key) + signServer, err := getAvaliableSignServer() // 获取可用签名服务器 + if err != nil { + log.Warn(err) + } + if signServer != nil && len(signServer.URL) > 1 { + log.Infof("使用签名服务器:%v", signServer.URL) go signStartRefreshToken(base.Account.RefreshInterval) // 定时刷新 token wrapper.DandelionEnergy = energy wrapper.FekitGetSign = sign if !base.IsBelow110 { if !base.Account.AutoRegister { - log.Warn("自动注册实例已关闭,若未配置 sign-server 端自动注册实例则实例丢失时需要重启 go-cqhttp 以正常签名") + log.Warn("自动注册实例已关闭,请配置 sign-server 端自动注册实例以保持正常签名") } if !base.Account.AutoRefreshToken { - log.Warn("自动刷新 token 已关闭,token 过期后获取签名时将不会立即尝试刷新获取新 token") + log.Info("自动刷新 token 已关闭,token 过期后获取签名时将不会立即尝试刷新获取新 token") } } else { log.Warn("签名服务器版本 <= 1.1.0 ,无法使用刷新 token 等操作,建议使用 1.1.6 版本及以上签名服务器") } } else { - log.Warnf("警告: 未配置签名服务器, 这可能会导致登录 45 错误码或发送消息被风控") + log.Warnf("警告: 未配置签名服务器或签名服务器不可用, 这可能会导致登录 45 错误码或发送消息被风控") } if base.Account.Encrypt { @@ -260,8 +255,14 @@ func LoginInteract() { versionFile := path.Join(global.VersionsPath, fmt.Sprint(int(cli.Device().Protocol))+".json") if global.PathExists(versionFile) { b, err := os.ReadFile(versionFile) - if err == nil { - _ = cli.Device().Protocol.Version().UpdateFromJson(b) + if err != nil { + log.Warnf("从文件 %s 读取本地版本信息文件出错.", versionFile) + os.Exit(0) + } + err = cli.Device().Protocol.Version().UpdateFromJson(b) + if err != nil { + log.Warnf("从文件 %s 解析本地版本信息出错: %v", versionFile, err) + os.Exit(0) } log.Infof("从文件 %s 读取协议版本 %v.", versionFile, cli.Device().Protocol.Version()) } @@ -320,7 +321,11 @@ func LoginInteract() { log.Infof("如果登录时出现版本过低错误, 可尝试使用 -update-protocol 参数启动") case !isTokenLogin: _ = device.Protocol.Version().UpdateFromJson(remoteVersion) + err := os.WriteFile(versionFile, remoteVersion, 0644) log.Infof("协议版本已更新: %s -> %s", currentVersionName, remoteVersionName) + if err != nil { + log.Warnln("更新协议版本缓存文件", versionFile, "失败:", err) + } default: log.Infof("检测到协议更新: %s -> %s", currentVersionName, remoteVersionName) log.Infof("由于使用了会话缓存, 无法自动更新协议, 请删除缓存后重试") @@ -343,7 +348,7 @@ func LoginInteract() { } var times uint = 1 // 重试次数 var reLoginLock sync.Mutex - cli.DisconnectedEvent.Subscribe(func(q *client.QQClient, e *client.ClientDisconnectedEvent) { + cli.DisconnectedEvent.Subscribe(func(_ *client.QQClient, e *client.ClientDisconnectedEvent) { reLoginLock.Lock() defer reLoginLock.Unlock() times = 1 @@ -456,7 +461,7 @@ func PasswordHashDecrypt(encryptedPasswordHash string, key []byte) ([]byte, erro func newClient() *client.QQClient { c := client.NewClientEmpty() c.UseFragmentMessage = base.ForceFragmented - c.OnServerUpdated(func(bot *client.QQClient, e *client.ServerUpdatedEvent) bool { + c.OnServerUpdated(func(_ *client.QQClient, _ *client.ServerUpdatedEvent) bool { if !base.UseSSOAddress { log.Infof("收到服务器地址更新通知, 根据配置文件已忽略.") return false @@ -488,7 +493,7 @@ func getRemoteLatestProtocolVersion(protocolType int) ([]byte, error) { } response, err := download.Request{URL: url}.Bytes() if err != nil { - return download.Request{URL: "https://ghproxy.com/" + url}.Bytes() + return download.Request{URL: "https://mirror.ghproxy.com/" + url}.Bytes() } return response, nil } diff --git a/cmd/gocq/qsign.go b/cmd/gocq/qsign.go new file mode 100644 index 000000000..345b131f5 --- /dev/null +++ b/cmd/gocq/qsign.go @@ -0,0 +1,427 @@ +package gocq + +import ( + "bytes" + "encoding/hex" + "fmt" + "io" + "net/http" + "strconv" + "strings" + "sync" + "sync/atomic" + "time" + + "github.com/pkg/errors" + log "github.com/sirupsen/logrus" + "github.com/tidwall/gjson" + + "github.com/Mrs4s/MiraiGo/utils" + + "github.com/Mrs4s/go-cqhttp/global" + "github.com/Mrs4s/go-cqhttp/internal/base" + "github.com/Mrs4s/go-cqhttp/internal/download" + "github.com/Mrs4s/go-cqhttp/modules/config" +) + +type currentSignServer atomic.Pointer[config.SignServer] + +func (c *currentSignServer) get() *config.SignServer { + if len(base.SignServers) == 1 { + // 只配置了一个签名服务时不检查以及切换, 在get阶段返回,防止返回nil导致其他bug(可能) + return &base.SignServers[0] + } + return (*atomic.Pointer[config.SignServer])(c).Load() +} + +func (c *currentSignServer) set(server *config.SignServer) { + (*atomic.Pointer[config.SignServer])(c).Store(server) +} + +// 当前签名服务器 +var ss currentSignServer + +// 失败计数 +type errconut atomic.Uintptr + +func (ec *errconut) hasOver(count uintptr) bool { + return (*atomic.Uintptr)(ec).Load() > count +} + +func (ec *errconut) inc() { + (*atomic.Uintptr)(ec).Add(1) +} + +var errn errconut + +// getAvaliableSignServer 获取可用的签名服务器,没有则返回空和相应错误 +func getAvaliableSignServer() (*config.SignServer, error) { + cs := ss.get() + if cs != nil { + return cs, nil + } + if len(base.SignServers) == 0 { + return nil, errors.New("no sign server configured") + } + maxCount := base.Account.MaxCheckCount + if maxCount == 0 { + if errn.hasOver(3) { + log.Warn("已连续 3 次获取不到可用签名服务器,将固定使用主签名服务器") + ss.set(&base.SignServers[0]) + return ss.get(), nil + } + } else if errn.hasOver(uintptr(maxCount)) { + log.Fatalf("获取可用签名服务器失败次数超过 %v 次, 正在离线", maxCount) + } + if cs != nil && len(cs.URL) > 0 { + log.Warnf("当前签名服务器 %v 不可用,正在查找可用服务器", cs.URL) + } + cs = asyncCheckServer(base.SignServers) + if cs == nil { + return nil, errors.New("no usable sign server") + } + return cs, nil +} + +func isServerAvaliable(signServer string) bool { + resp, err := download.Request{ + Method: http.MethodGet, + URL: signServer, + }.WithTimeout(3 * time.Second).Bytes() + if err == nil && gjson.GetBytes(resp, "code").Int() == 0 { + return true + } + log.Warnf("签名服务器 %v 可能不可用,请求出现错误:%v", signServer, err) + return false +} + +// asyncCheckServer 按同步顺序检查所有签名服务器直到找到可用的 +func asyncCheckServer(servers []config.SignServer) *config.SignServer { + doRegister := sync.Once{} + wg := sync.WaitGroup{} + wg.Add(len(servers)) + for i, s := range servers { + go func(i int, server config.SignServer) { + defer wg.Done() + log.Infof("检查签名服务器:%v (%v/%v)", server.URL, i+1, len(servers)) + if len(server.URL) < 4 { + return + } + if isServerAvaliable(server.URL) { + doRegister.Do(func() { + ss.set(&server) + log.Infof("使用签名服务器 url=%v, key=%v, auth=%v", server.URL, server.Key, server.Authorization) + if base.Account.AutoRegister { + // 若配置了自动注册实例则在切换后注册实例,否则不需要注册,签名时由qsign自动注册 + signRegister(base.Account.Uin, device.AndroidId, device.Guid, device.QImei36, server.Key) + } + }) + } + }(i, s) + } + wg.Wait() + return ss.get() +} + +/* +请求签名服务器 + + url: api + params 组合的字符串,无须包含签名服务器地址 + return: signServer, response, error +*/ +func requestSignServer(method string, url string, headers map[string]string, body io.Reader) (string, []byte, error) { + signServer, e := getAvaliableSignServer() + if e != nil && len(signServer.URL) == 0 { // 没有可用的 + log.Warnf("获取可用签名服务器出错:%v, 将使用主签名服务器进行签名", e) + errn.inc() + signServer = &base.SignServers[0] // 没有获取到时使用第一个 + } + if !strings.HasPrefix(url, signServer.URL) { + url = strings.TrimSuffix(signServer.URL, "/") + "/" + strings.TrimPrefix(url, "/") + } + if headers == nil { + headers = map[string]string{} + } + auth := signServer.Authorization + if auth != "-" && auth != "" { + headers["Authorization"] = auth + } + req := download.Request{ + Method: method, + Header: headers, + URL: url, + Body: body, + }.WithTimeout(time.Duration(base.SignServerTimeout) * time.Second) + resp, err := req.Bytes() + if err != nil { + ss.set(nil) // 标记为不可用 + } + return signServer.URL, resp, err +} + +func energy(uin uint64, id string, _ string, salt []byte) ([]byte, error) { + url := "custom_energy" + fmt.Sprintf("?data=%v&salt=%v&uin=%v&android_id=%v&guid=%v", + id, hex.EncodeToString(salt), uin, utils.B2S(device.AndroidId), hex.EncodeToString(device.Guid)) + if base.IsBelow110 { + url = "custom_energy" + fmt.Sprintf("?data=%v&salt=%v", id, hex.EncodeToString(salt)) + } + signServer, response, err := requestSignServer(http.MethodGet, url, nil, nil) + if err != nil { + log.Warnf("获取T544 sign时出现错误: %v. server: %v", err, signServer) + return nil, err + } + data, err := hex.DecodeString(gjson.GetBytes(response, "data").String()) + if err != nil { + log.Warnf("获取T544 sign时出现错误: %v (data: %v)", err, gjson.GetBytes(response, "data").String()) + return nil, err + } + if len(data) == 0 { + log.Warnf("获取T544 sign时出现错误: %v.", "data is empty") + return nil, errors.New("data is empty") + } + return data, nil +} + +// signSubmit +// 提交回调 buffer +func signSubmit(uin string, cmd string, callbackID int64, buffer []byte, t string) { + buffStr := hex.EncodeToString(buffer) + if base.Debug { + tail := 64 + endl := "..." + if len(buffStr) < tail { + tail = len(buffStr) + endl = "." + } + log.Debugf("submit (%v): uin=%v, cmd=%v, callbackID=%v, buffer=%v%s", t, uin, cmd, callbackID, buffStr[:tail], endl) + } + + signServer, _, err := requestSignServer( + http.MethodGet, + "submit"+fmt.Sprintf("?uin=%v&cmd=%v&callback_id=%v&buffer=%v", + uin, cmd, callbackID, buffStr), + nil, nil, + ) + if err != nil { + log.Warnf("提交 callback 时出现错误: %v. server: %v", err, signServer) + } +} + +// signCallback +// 刷新 token 和签名的回调 +func signCallback(uin string, results []gjson.Result, t string) { + for { // 等待至在线 + if cli.Online.Load() { + break + } + time.Sleep(1 * time.Second) + } + for _, result := range results { + cmd := result.Get("cmd").String() + callbackID := result.Get("callbackId").Int() + body, _ := hex.DecodeString(result.Get("body").String()) + ret, err := cli.SendSsoPacket(cmd, body) + if err != nil || len(ret) == 0 { + log.Warnf("Callback error: %v, or response data is empty", err) + continue // 发送 SsoPacket 出错或返回数据为空时跳过 + } + signSubmit(uin, cmd, callbackID, ret, t) + } +} + +func signRequset(seq uint64, uin string, cmd string, qua string, buff []byte) (sign []byte, extra []byte, token []byte, err error) { + headers := map[string]string{"Content-Type": "application/x-www-form-urlencoded"} + _, response, err := requestSignServer( + http.MethodPost, + "sign", + headers, + bytes.NewReader([]byte(fmt.Sprintf("uin=%v&qua=%s&cmd=%s&seq=%v&buffer=%v&android_id=%v&guid=%v", + uin, qua, cmd, seq, hex.EncodeToString(buff), utils.B2S(device.AndroidId), hex.EncodeToString(device.Guid)))), + ) + if err != nil { + return nil, nil, nil, err + } + sign, _ = hex.DecodeString(gjson.GetBytes(response, "data.sign").String()) + extra, _ = hex.DecodeString(gjson.GetBytes(response, "data.extra").String()) + token, _ = hex.DecodeString(gjson.GetBytes(response, "data.token").String()) + if !base.IsBelow110 { + go signCallback(uin, gjson.GetBytes(response, "data.requestCallback").Array(), "sign") + } + return sign, extra, token, nil +} + +var registerLock sync.Mutex + +func signRegister(uin int64, androidID, guid []byte, qimei36, key string) { + if base.IsBelow110 { + log.Warn("签名服务器版本低于1.1.0, 跳过实例注册") + return + } + signServer, resp, err := requestSignServer( + http.MethodGet, + "register"+fmt.Sprintf("?uin=%v&android_id=%v&guid=%v&qimei36=%v&key=%s", + uin, utils.B2S(androidID), hex.EncodeToString(guid), qimei36, key), + nil, nil, + ) + if err != nil { + log.Warnf("注册QQ实例时出现错误: %v. server: %v", err, signServer) + return + } + msg := gjson.GetBytes(resp, "msg") + if gjson.GetBytes(resp, "code").Int() != 0 { + log.Warnf("注册QQ实例时出现错误: %v. server: %v", msg, signServer) + return + } + log.Infof("注册QQ实例 %v 成功: %v", uin, msg) +} + +func signRefreshToken(uin string) error { + log.Info("正在刷新 token") + _, resp, err := requestSignServer( + http.MethodGet, + "request_token?uin="+uin, + nil, nil, + ) + if err != nil { + return err + } + msg := gjson.GetBytes(resp, "msg") + code := gjson.GetBytes(resp, "code") + if code.Int() != 0 { + return errors.New("code=" + code.String() + ", msg: " + msg.String()) + } + go signCallback(uin, gjson.GetBytes(resp, "data").Array(), "request token") + return nil +} + +var missTokenCount = uint64(0) +var lastToken = "" + +func sign(seq uint64, uin string, cmd string, qua string, buff []byte) (sign []byte, extra []byte, token []byte, err error) { + i := 0 + for { + sign, extra, token, err = signRequset(seq, uin, cmd, qua, buff) + cs := ss.get() + if cs == nil { + // 最好在请求后判断,否则若被设置为nil后不会再请求签名, + // 导致在下一次有请求签名服务操作之前,ss无法更新 + err = errors.New("nil signserver") + log.Warn("nil sign-server") // 返回的err并不会log出来,加条日志 + return + } + if err != nil { + log.Warnf("获取sso sign时出现错误: %v. server: %v", err, cs.URL) + } + if i > 0 { + break + } + i++ + if (!base.IsBelow110) && base.Account.AutoRegister && err == nil && len(sign) == 0 { + if registerLock.TryLock() { // 避免并发时多处同时销毁并重新注册 + log.Debugf("请求签名:cmd=%v, qua=%v, buff=%v", seq, cmd, hex.EncodeToString(buff)) + log.Debugf("返回结果:sign=%v, extra=%v, token=%v", + hex.EncodeToString(sign), hex.EncodeToString(extra), hex.EncodeToString(token)) + log.Warn("获取签名为空,实例可能丢失,正在尝试重新注册") + defer registerLock.Unlock() + err := signServerDestroy(uin) + if err != nil { + log.Warnln(err) // 实例真的丢失时则必出错,或许应该不 return , 以重新获取本次签名 + // return nil, nil, nil, err + } + signRegister(base.Account.Uin, device.AndroidId, device.Guid, device.QImei36, cs.Key) + } + continue + } + if (!base.IsBelow110) && base.Account.AutoRefreshToken && len(token) == 0 { + log.Warnf("token 已过期, 总丢失 token 次数为 %v", atomic.AddUint64(&missTokenCount, 1)) + if registerLock.TryLock() { + defer registerLock.Unlock() + if err := signRefreshToken(uin); err != nil { + log.Warnf("刷新 token 出现错误: %v. server: %v", err, cs.URL) + } else { + log.Info("刷新 token 成功") + } + } + continue + } + break + } + if tokenString := hex.EncodeToString(token); lastToken != tokenString { + log.Infof("token 已更新:%v -> %v", lastToken, tokenString) + lastToken = tokenString + } + rule := base.Account.RuleChangeSignServer + if (len(sign) == 0 && rule >= 1) || (len(token) == 0 && rule >= 2) { + ss.set(nil) + } + return sign, extra, token, err +} + +func signServerDestroy(uin string) error { + signServer, signVersion, err := signVersion() + if err != nil { + return errors.Wrapf(err, "获取签名服务版本出现错误, server: %v", signServer) + } + if global.VersionNameCompare("v"+signVersion, "v1.1.6") { + return errors.Errorf("当前签名服务器版本 %v 低于 1.1.6,无法使用 destroy 接口", signVersion) + } + cs := ss.get() + if cs == nil { + return errors.New("nil signserver") + } + signServer, resp, err := requestSignServer( + http.MethodGet, + "destroy"+fmt.Sprintf("?uin=%v&key=%v", uin, cs.Key), + nil, nil, + ) + if err != nil || gjson.GetBytes(resp, "code").Int() != 0 { + return errors.Wrapf(err, "destroy 实例出现错误, server: %v", signServer) + } + return nil +} + +func signVersion() (signServer string, version string, err error) { + signServer, resp, err := requestSignServer(http.MethodGet, "", nil, nil) + if err != nil { + return signServer, "", err + } + if gjson.GetBytes(resp, "code").Int() == 0 { + return signServer, gjson.GetBytes(resp, "data.version").String(), nil + } + return signServer, "", errors.New("empty version") +} + +// 定时刷新 token, interval 为间隔时间(分钟) +func signStartRefreshToken(interval int64) { + if interval <= 0 { + log.Warn("定时刷新 token 已关闭") + return + } + log.Infof("每 %v 分钟将刷新一次签名 token", interval) + if interval < 10 { + log.Warnf("间隔时间 %v 分钟较短,推荐 30~40 分钟", interval) + } + if interval > 60 { + log.Warn("间隔时间不能超过 60 分钟,已自动设置为 60 分钟") + interval = 60 + } + t := time.NewTicker(time.Duration(interval) * time.Minute) + qqstr := strconv.FormatInt(base.Account.Uin, 10) + defer t.Stop() + for range t.C { + cs, master := ss.get(), &base.SignServers[0] + if (cs == nil || cs.URL != master.URL) && isServerAvaliable(master.URL) { + ss.set(master) + log.Infof("主签名服务器可用,已切换至主签名服务器 %v", master.URL) + } + cs = ss.get() + if cs == nil { + log.Warn("无法获得可用签名服务器,停止 token 定时刷新") + return + } + err := signRefreshToken(qqstr) + if err != nil { + log.Warnf("刷新 token 出现错误: %v. server: %v", err, cs.URL) + } + } +} diff --git a/coolq/api.go b/coolq/api.go index 1f18ad1f0..c129b329f 100644 --- a/coolq/api.go +++ b/coolq/api.go @@ -759,7 +759,7 @@ func (bot *CQBot) CQSendGroupMessage(groupID int64, m gjson.Result, autoEscape b } else { str := m.String() if str == "" { - log.Warn("群消息发送失败: 信息为空.") + log.Warnf("群 %v 消息发送失败: 信息为空.", groupID) return Failed(100, "EMPTY_MSG_ERROR", "消息为空") } if autoEscape { @@ -981,7 +981,7 @@ func (bot *CQBot) CQSendGroupForwardMessage(groupID int64, m gjson.Result) globa } ret := bot.Client.SendGroupForwardMessage(groupID, fe) if ret == nil || ret.Id == -1 { - log.Warnf("合并转发(群)消息发送失败: 账号可能被风控.") + log.Warnf("合并转发(群 %v)消息发送失败: 账号可能被风控.", groupID) return Failed(100, "SEND_MSG_API_ERROR", "请参考 go-cqhttp 端输出") } mid := bot.InsertGroupMessage(ret, source) @@ -1007,7 +1007,7 @@ func (bot *CQBot) CQSendPrivateForwardMessage(userID int64, m gjson.Result) glob } mid := bot.SendPrivateMessage(userID, 0, &message.SendingMessage{Elements: []message.IMessageElement{fe}}) if mid == -1 { - log.Warnf("合并转发(好友)消息发送失败: 账号可能被风控.") + log.Warnf("合并转发(好友 %v)消息发送失败: 账号可能被风控.", userID) return Failed(100, "SEND_MSG_API_ERROR", "请参考 go-cqhttp 端输出") } log.Infof("发送好友 %v(%v) 的合并转发消息: %v (%v)", userID, userID, limitedString(m.String()), mid) @@ -1388,33 +1388,42 @@ func (bot *CQBot) CQGetGroupHonorInfo(groupID int64, t string) global.MSG { } } msg["talkative_list"] = convertMem(honor.TalkativeList) + } else { + log.Infof("获取群龙王出错:%v", err) } } if t == "performer" || t == "all" { if honor, err := bot.Client.GetGroupHonorInfo(groupID, client.Performer); err == nil { msg["performer_list"] = convertMem(honor.ActorList) + } else { + log.Infof("获取群聊之火出错:%v", err) } } if t == "legend" || t == "all" { if honor, err := bot.Client.GetGroupHonorInfo(groupID, client.Legend); err == nil { msg["legend_list"] = convertMem(honor.LegendList) + } else { + log.Infof("获取群聊炽焰出错:%v", err) } } if t == "strong_newbie" || t == "all" { if honor, err := bot.Client.GetGroupHonorInfo(groupID, client.StrongNewbie); err == nil { msg["strong_newbie_list"] = convertMem(honor.StrongNewbieList) + } else { + log.Infof("获取冒尖小春笋出错:%v", err) } } if t == "emotion" || t == "all" { if honor, err := bot.Client.GetGroupHonorInfo(groupID, client.Emotion); err == nil { msg["emotion_list"] = convertMem(honor.EmotionList) + } else { + log.Infof("获取快乐之源出错:%v", err) } } - return OK(msg) } @@ -1689,26 +1698,8 @@ func (bot *CQBot) CQGetMessage(messageID int32) global.MSG { switch o := msg.(type) { case *db.StoredGroupMessage: m["group_id"] = o.GroupCode - if o.QuotedInfo != nil { - elem := global.MSG{ - "type": "reply", - "data": global.MSG{ - "id": strconv.FormatInt(int64(o.QuotedInfo.PrevGlobalID), 10), - }, - } - o.Content = append(o.Content, elem) - } m["message"] = ToFormattedMessage(bot.ConvertContentMessage(o.Content, message.SourceGroup, false), message.Source{SourceType: message.SourceGroup, PrimaryID: o.GroupCode}) case *db.StoredPrivateMessage: - if o.QuotedInfo != nil { - elem := global.MSG{ - "type": "reply", - "data": global.MSG{ - "id": strconv.FormatInt(int64(o.QuotedInfo.PrevGlobalID), 10), - }, - } - o.Content = append(o.Content, elem) - } m["message"] = ToFormattedMessage(bot.ConvertContentMessage(o.Content, message.SourcePrivate, false), message.Source{SourceType: message.SourcePrivate}) } return OK(m) diff --git a/coolq/bot.go b/coolq/bot.go index e2e323146..ca6d72661 100644 --- a/coolq/bot.go +++ b/coolq/bot.go @@ -297,14 +297,14 @@ func (bot *CQBot) SendGroupMessage(groupID int64, m *message.SendingMessage) (in newElem = append(newElem, e) } if len(newElem) == 0 { - log.Warnf("群消息发送失败: 消息为空.") + log.Warnf("群 %v 消息发送失败: 消息为空.", groupID) return -1, errors.New("empty message") } m.Elements = newElem bot.checkMedia(newElem, groupID) ret := bot.Client.SendGroupMessage(groupID, m) if ret == nil || ret.Id == -1 { - log.Warnf("群消息发送失败: 账号可能被风控.") + log.Warnf("群 %v 发送消息失败: 账号可能被风控.", groupID) return -1, errors.New("send group message failed: blocked by server") } return bot.InsertGroupMessage(ret, source), nil diff --git a/coolq/cqcode.go b/coolq/cqcode.go index 1ce3dd2ac..c7d740e16 100644 --- a/coolq/cqcode.go +++ b/coolq/cqcode.go @@ -243,6 +243,16 @@ func toElements(e []message.IMessageElement, source message.Source) (r []msg.Ele {K: "type", V: "sticker"}, }, } + case *message.GroupFileElement: + m = msg.Element{ + Type: "file", + Data: pairs{ + {K: "path", V: o.Path}, + {K: "name", V: o.Name}, + {K: "size", V: strconv.FormatInt(o.Size, 10)}, + {K: "busid", V: strconv.FormatInt(int64(o.Busid), 10)}, + }, + } case *msg.LocalImage: data := pairs{ {K: "file", V: o.File}, @@ -378,6 +388,11 @@ func ToMessageContent(e []message.IMessageElement, source message.Source) (r []g "type": "face", "data": global.MSG{"id": o.ID, "type": "sticker"}, } + case *message.GroupFileElement: + m = global.MSG{ + "type": "file", + "data": global.MSG{"path": o.Path, "name": o.Name, "size": strconv.FormatInt(o.Size, 10), "busid": strconv.FormatInt(int64(o.Busid), 10)}, + } default: continue } @@ -389,7 +404,7 @@ func ToMessageContent(e []message.IMessageElement, source message.Source) (r []g // ConvertStringMessage 将消息字符串转为消息元素数组 func (bot *CQBot) ConvertStringMessage(spec *onebot.Spec, raw string, sourceType message.SourceType) (r []message.IMessageElement) { elems := msg.ParseString(raw) - return bot.ConvertElements(spec, elems, sourceType, true) + return bot.ConvertElements(spec, elems, sourceType, false) } // ConvertObjectMessage 将消息JSON对象转为消息元素数组 @@ -849,6 +864,17 @@ func (bot *CQBot) ConvertElement(spec *onebot.Spec, elem msg.Element, sourceType v.File = cacheFile } return v, nil + case "file": + path := elem.Get("path") + name := elem.Get("name") + size, _ := strconv.ParseInt(elem.Get("size"), 10, 64) + busid, _ := strconv.ParseInt(elem.Get("busid"), 10, 64) + return &message.GroupFileElement{ + Name: name, + Size: size, + Path: path, + Busid: int32(busid), + }, nil default: return nil, errors.New("unsupported message type: " + elem.Type) } diff --git a/coolq/event.go b/coolq/event.go index 61e763f48..9081985dd 100644 --- a/coolq/event.go +++ b/coolq/event.go @@ -118,7 +118,7 @@ func (bot *CQBot) groupMessageEvent(c *client.QQClient, m *message.GroupMessage) "url": c.GetGroupFileUrl(m.GroupCode, file.Path, file.Busid), }, }) - return + // return } } source := message.Source{ diff --git a/go.mod b/go.mod index 8ea6e36e7..66f7881ed 100644 --- a/go.mod +++ b/go.mod @@ -3,28 +3,28 @@ module github.com/Mrs4s/go-cqhttp go 1.20 require ( - github.com/FloatTech/sqlite v1.5.7 - github.com/Microsoft/go-winio v0.6.0 - github.com/Mrs4s/MiraiGo v0.0.0-20230730133947-d344e0f318ab + github.com/FloatTech/sqlite v1.6.3 + github.com/Microsoft/go-winio v0.6.2-0.20230724192519-b29bbd58a65a + github.com/Mrs4s/MiraiGo v0.0.0-20230823050531-a8213e127b2b github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e - github.com/RomiChan/websocket v1.4.3-0.20220123145318-307a86b127bc - github.com/fumiama/go-base16384 v1.6.1 + github.com/RomiChan/websocket v1.4.3-0.20220227141055-9b2c6168c9c5 + github.com/fumiama/go-base16384 v1.7.0 github.com/fumiama/go-hide-param v0.1.4 github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible github.com/mattn/go-colorable v0.1.13 github.com/pkg/errors v0.9.1 github.com/segmentio/asm v1.2.0 - github.com/sirupsen/logrus v1.9.0 + github.com/sirupsen/logrus v1.9.3 github.com/stretchr/testify v1.8.1 - github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 - github.com/tidwall/gjson v1.14.4 + github.com/syndtr/goleveldb v1.0.0 + github.com/tidwall/gjson v1.15.0 github.com/wdvxdr1123/go-silk v0.0.0-20210316130616-d47b553def60 - go.mongodb.org/mongo-driver v1.11.0 - golang.org/x/crypto v0.3.0 - golang.org/x/image v0.5.0 - golang.org/x/sys v0.2.0 - golang.org/x/term v0.2.0 - golang.org/x/time v0.2.0 + go.mongodb.org/mongo-driver v1.12.0 + golang.org/x/crypto v0.17.0 + golang.org/x/image v0.10.0 + golang.org/x/sys v0.15.0 + golang.org/x/term v0.15.0 + golang.org/x/time v0.3.0 gopkg.ilharper.com/x/isatty v1.1.1 gopkg.in/yaml.v3 v3.0.1 ) @@ -39,6 +39,7 @@ require ( github.com/jonboulle/clockwork v0.3.0 // indirect github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect github.com/klauspost/compress v1.13.6 // indirect + github.com/kr/pretty v0.3.1 // indirect github.com/lestrrat-go/strftime v1.0.6 // indirect github.com/mattn/go-isatty v0.0.16 // indirect github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect @@ -48,13 +49,13 @@ require ( github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect - github.com/xdg-go/scram v1.1.1 // indirect - github.com/xdg-go/stringprep v1.0.3 // indirect + github.com/xdg-go/scram v1.1.2 // indirect + github.com/xdg-go/stringprep v1.0.4 // indirect github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect - golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect - golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde // indirect - golang.org/x/text v0.7.0 // indirect - golang.org/x/tools v0.1.12 // indirect + golang.org/x/mod v0.12.0 // indirect + golang.org/x/sync v0.3.0 // indirect + golang.org/x/text v0.14.0 // indirect + golang.org/x/tools v0.11.0 // indirect lukechampine.com/uint128 v1.2.0 // indirect modernc.org/cc/v3 v3.40.0 // indirect modernc.org/ccgo/v3 v3.16.13 // indirect diff --git a/go.sum b/go.sum index 61e86aec6..29134641b 100644 --- a/go.sum +++ b/go.sum @@ -1,48 +1,40 @@ -github.com/FloatTech/sqlite v1.5.7 h1:Bvo4LSojcZ6dVtbHrkqvt6z4v8e+sj0G5PSUIvdawsk= -github.com/FloatTech/sqlite v1.5.7/go.mod h1:zFbHzRfB+CJ+VidfjuVbrcin3DAz283F7hF1hIeHzpY= +github.com/FloatTech/sqlite v1.6.3 h1:MQkqBNlkPuCoKQQgoNLuTL/2Ci3tBTFAnVYBdD0Wy4M= +github.com/FloatTech/sqlite v1.6.3/go.mod h1:zFbHzRfB+CJ+VidfjuVbrcin3DAz283F7hF1hIeHzpY= github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b h1:tvciXWq2nuvTbFeJGLDNIdRX3BI546D3O7k7vrVueZw= github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b/go.mod h1:fHZFWGquNXuHttu9dUYoKuNbm3dzLETnIOnm1muSfDs= -github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg= -github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE= -github.com/Mrs4s/MiraiGo v0.0.0-20230730133947-d344e0f318ab h1:SLciJTlC5YiG3qqvGJf4sHJDHDXUdH+v4rjqVhE5SIQ= -github.com/Mrs4s/MiraiGo v0.0.0-20230730133947-d344e0f318ab/go.mod h1:mU3fBFU+7eO0kaGes7YRKtzIDtwIU84nSSwTV7NK2b0= +github.com/Microsoft/go-winio v0.6.2-0.20230724192519-b29bbd58a65a h1:aU1703IHxupjzipvhu16qYKLMR03e+8WuNR+JMsKfGU= +github.com/Microsoft/go-winio v0.6.2-0.20230724192519-b29bbd58a65a/go.mod h1:OZqLNXdYJHmx7aqq/T6wAdFEdoGm5nmIfC4kU7M8P8o= +github.com/Mrs4s/MiraiGo v0.0.0-20230823050531-a8213e127b2b h1:0GG6kDFgzie0HNdlkrgPwyX4WqUjckTP1xTM4cYaC2g= +github.com/Mrs4s/MiraiGo v0.0.0-20230823050531-a8213e127b2b/go.mod h1:mU3fBFU+7eO0kaGes7YRKtzIDtwIU84nSSwTV7NK2b0= github.com/RomiChan/protobuf v0.1.1-0.20230204044148-2ed269a2e54d h1:/Xuj3fIiMY2ls1TwvPKmaqQrtJsPY+c9s+0lOScVHd8= github.com/RomiChan/protobuf v0.1.1-0.20230204044148-2ed269a2e54d/go.mod h1:2Ie+hdBFQpQFDHfeklgxoFmQRCE7O+KwFpISeXq7OwA= github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e h1:wR3MXQ3VbUlPKOOUwLOYgh/QaJThBTYtsl673O3lqSA= github.com/RomiChan/syncx v0.0.0-20221202055724-5f842c53020e/go.mod h1:vD7Ra3Q9onRtojoY5sMCLQ7JBgjUsrXDnDKyFxqpf9w= -github.com/RomiChan/websocket v1.4.3-0.20220123145318-307a86b127bc h1:AAx50/fb/xS4lvsdQg+bFbGvqSDhyV1MF+p2PLCamZ0= -github.com/RomiChan/websocket v1.4.3-0.20220123145318-307a86b127bc/go.mod h1:OMmITAib6POA37xCichWM0aRnoVpSMZO1rB/G01wrr0= +github.com/RomiChan/websocket v1.4.3-0.20220227141055-9b2c6168c9c5 h1:bBmmB7he0iVN4m5mcehfheeRUEer/Avo4ujnxI3uCqs= +github.com/RomiChan/websocket v1.4.3-0.20220227141055-9b2c6168c9c5/go.mod h1:0UcFaCkhp6vZw6l5Dpq0Dp673CoF9GdvA8lTfst0GiU= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= -github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fumiama/go-base16384 v1.6.1 h1:4yb4JgmBJDnQtq3XGXXdLrVwEnRpjhMUt4eAcsNeA30= -github.com/fumiama/go-base16384 v1.6.1/go.mod h1:OEn+947GV5gsbTAnyuUW/SrfxJYUdYupSIQXOuGOcXM= +github.com/fumiama/go-base16384 v1.7.0 h1:6fep7XPQWxRlh4Hu+KsdH+6+YdUp+w6CwRXtMWSsXCA= +github.com/fumiama/go-base16384 v1.7.0/go.mod h1:OEn+947GV5gsbTAnyuUW/SrfxJYUdYupSIQXOuGOcXM= github.com/fumiama/go-hide-param v0.1.4 h1:y7TRTzZMdCH9GOXnIzU3B+1BSkcmvejVGmGsz4t0DGU= github.com/fumiama/go-hide-param v0.1.4/go.mod h1:vJkQlJIEI56nIyp7tCQu1/2QOyKtZpudsnJkGk9U1aY= github.com/fumiama/imgsz v0.0.2 h1:fAkC0FnIscdKOXwAxlyw3EUba5NzxZdSxGaq3Uyfxak= github.com/fumiama/imgsz v0.0.2/go.mod h1:dR71mI3I2O5u6+PCpd47M9TZptzP+39tRBcbdIkoqM4= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ= github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jonboulle/clockwork v0.3.0 h1:9BSCMi8C+0qdApAp4auwX0RkLGUjs956h0EkuQymUhg= github.com/jonboulle/clockwork v0.3.0/go.mod h1:Pkfl5aHPm1nk2H9h0bjmnJD/BcgbGXUBGnn1kMkgxc8= @@ -50,11 +42,10 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNU github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2ttpEmkA4aQ3j4u9dStX2t4M8UM6qqNsG8= github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is= github.com/lestrrat-go/file-rotatelogs v2.4.0+incompatible h1:Y6sqxHMyB1D2YSzWkLibYKgg+SwmyFU9dF2hn6MdTj4= @@ -69,17 +60,14 @@ github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= -github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78= -github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= -github.com/onsi/ginkgo v1.14.0 h1:2mOpI4JVVPBN+WQRa0WKH2eXR+Ey+uK4n7Zj0aYpIQA= -github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY= -github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= -github.com/onsi/gomega v1.10.1 h1:o0+MgICZLuZ7xjH7Vx6zS/zcu93/BEp1VwkIW1mEXCE= -github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/ginkgo v1.7.0 h1:WSHQ+IS43OoUrWtD1/bbclrwK8TTH5hzp+umCiuxHgs= +github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.4.3 h1:RE1xgDvH7imwFD45h+u2SgIfERHlS2yNG4DObb5BSKU= +github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/pierrec/lz4/v4 v4.1.15 h1:MO0/ucJhngq7299dKLwIMtgTfbkoSPF6AoMYDd8Q4q0= github.com/pierrec/lz4/v4 v4.1.15/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -87,126 +75,115 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE= github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys= github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs= -github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= -github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= -github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= -github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= -github.com/tidwall/gjson v1.14.4/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= +github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE= +github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= +github.com/tidwall/gjson v1.15.0 h1:5n/pM+v3r5ujuNl4YLZLsQ+UE5jlkLVm7jMzT5Mpolw= +github.com/tidwall/gjson v1.15.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= github.com/wdvxdr1123/go-silk v0.0.0-20210316130616-d47b553def60 h1:lRKf10iIOW0VsH5WDF621ihzR+R2wEBZVtNRHuLLCb4= github.com/wdvxdr1123/go-silk v0.0.0-20210316130616-d47b553def60/go.mod h1:ecFKZPX81BaB70I6ruUgEwYcDOtuNgJGnjdK+MIl5ko= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= -github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E= -github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g= -github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs= -github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8= +github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= +github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= +github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= +github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA= github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.mongodb.org/mongo-driver v1.11.0 h1:FZKhBSTydeuffHj9CBjXlR8vQLee1cQyTWYPA6/tqiE= -go.mongodb.org/mongo-driver v1.11.0/go.mod h1:s7p5vEtfbeR1gYi6pnj3c3/urpbLv2T5Sfd6Rp2HBB8= +go.mongodb.org/mongo-driver v1.12.0 h1:aPx33jmn/rQuJXPQLZQ8NtfPQG8CaqgLThFtqRb0PiE= +go.mongodb.org/mongo-driver v1.12.0/go.mod h1:AZkxhPnFJUoH7kZlFkVKucV20K387miPfm7oimrSmK0= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.3.0 h1:a06MkbcxBrEFc0w0QIZWXrH/9cCX6KJyWbBOIwAn+7A= -golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/image v0.5.0 h1:5JMiNunQeQw++mMOz48/ISeNu3Iweh/JaZU8ZLqHRrI= -golang.org/x/image v0.5.0/go.mod h1:FVC7BI/5Ym8R25iw5OLsgshdUBbT1h5jZTpA+mvAdZ4= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= +golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/image v0.10.0 h1:gXjUUtwtx5yOE0VKWq1CH4IJAClq4UGgUA3i+rpON9M= +golang.org/x/image v0.10.0/go.mod h1:jtrku+n79PfroUbvDdeUWMAI+heR786BofxrbiSF+J0= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20200813134508-3edf25e44fcc/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.2.0 h1:sZfSu1wtKLGlWI4ZZayP0ck9Y73K1ynO6gqzTdBVdPU= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.12.0 h1:cfawfvKITfUsFCeJIHJrbSxpeu/E81khclypR0GVT50= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde h1:ejfdSekXMDxDLbRrJMwUk6KnSLZ2McaUCVcIKM+N6jc= -golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= +golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200814200057-3d37ad5750ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201126233918-771906719818/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220111092808-5a964db01320/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.2.0 h1:ljd4t30dBnAvMZaQCevtY0xLLD0A+bRZXbgLMLU1F/A= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.2.0 h1:z85xZCsEl7bi/KwbNADeBYoOP0++7W1ipu+aGnpwzRM= -golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/time v0.2.0 h1:52I/1L54xyEQAYdtcSuxtiT84KGYTBGXwayxmIpNJhE= -golang.org/x/time v0.2.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/text v0.11.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/tools v0.11.0 h1:EMCa6U9S2LtZXLAMoWiR/R8dAQFRqbAitmbJ2UKhoi8= +golang.org/x/tools v0.11.0/go.mod h1:anzJrxPjNtfgiYQYirP2CPGzGLxrH2u2QBhn6Bf3qY8= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= gopkg.ilharper.com/x/isatty v1.1.1 h1:RAg32Pxq/nIK4AVtdm9RBqxsxZZX1uRKRSS21E5SHMk= gopkg.ilharper.com/x/isatty v1.1.1/go.mod h1:ofpv77Td5qQO6R1dmDd3oNt8TZdRo+l5gYAMxopRyS0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= -gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/base/flag.go b/internal/base/flag.go index 8e0c37ac6..105fad5a5 100644 --- a/internal/base/flag.go +++ b/internal/base/flag.go @@ -23,27 +23,25 @@ var ( // config file flags var ( - Debug bool // 是否开启 debug 模式 - RemoveReplyAt bool // 是否删除reply后的at - ExtraReplyData bool // 是否上报额外reply信息 - IgnoreInvalidCQCode bool // 是否忽略无效CQ码 - SplitURL bool // 是否分割URL - ForceFragmented bool // 是否启用强制分片 - SkipMimeScan bool // 是否跳过Mime扫描 - ConvertWebpImage bool // 是否转换Webp图片 - ReportSelfMessage bool // 是否上报自身消息 - UseSSOAddress bool // 是否使用服务器下发的新地址进行重连 - LogForceNew bool // 是否在每次启动时强制创建全新的文件储存日志 - LogColorful bool // 是否启用日志颜色 - FastStart bool // 是否为快速启动 - AllowTempSession bool // 是否允许发送临时会话信息 - UpdateProtocol bool // 是否更新协议 - SignServer string // 使用特定的服务器进行签名 - SignServerBearer string // 认证签名服务器的 Bearer Token - Key string // 签名服务器密钥 - IsBelow110 bool // 签名服务器版本是否低于1.1.0及以下 - HTTPTimeout int // download 超时时间 - SignServerTimeout int // 签名服务器超时时间 + Debug bool // 是否开启 debug 模式 + RemoveReplyAt bool // 是否删除reply后的at + ExtraReplyData bool // 是否上报额外reply信息 + IgnoreInvalidCQCode bool // 是否忽略无效CQ码 + SplitURL bool // 是否分割URL + ForceFragmented bool // 是否启用强制分片 + SkipMimeScan bool // 是否跳过Mime扫描 + ConvertWebpImage bool // 是否转换Webp图片 + ReportSelfMessage bool // 是否上报自身消息 + UseSSOAddress bool // 是否使用服务器下发的新地址进行重连 + LogForceNew bool // 是否在每次启动时强制创建全新的文件储存日志 + LogColorful bool // 是否启用日志颜色 + FastStart bool // 是否为快速启动 + AllowTempSession bool // 是否允许发送临时会话信息 + UpdateProtocol bool // 是否更新协议 + SignServers []config.SignServer // 使用特定的服务器进行签名 + IsBelow110 bool // 签名服务器版本是否低于1.1.0及以下 + HTTPTimeout int // download 超时时间 + SignServerTimeout int // 签名服务器超时时间 PostFormat string // 上报格式 string or array Proxy string // 存储 proxy_rewrite,用于设置代理 @@ -92,12 +90,10 @@ func Init() { ReportSelfMessage = conf.Message.ReportSelfMessage UseSSOAddress = conf.Account.UseSSOAddress AllowTempSession = conf.Account.AllowTempSession - SignServer = conf.Account.SignServer - SignServerBearer = conf.Account.SignServerBearer - Key = conf.Account.Key + SignServers = conf.Account.SignServers IsBelow110 = conf.Account.IsBelow110 HTTPTimeout = conf.Message.HTTPTimeout - SignServerTimeout = conf.Message.SignServerTimeout + SignServerTimeout = int(conf.Account.SignServerTimeout) } { // others Proxy = conf.Message.ProxyRewrite diff --git a/internal/download/download.go b/internal/download/download.go index 786658f32..c130f96e1 100644 --- a/internal/download/download.go +++ b/internal/download/download.go @@ -15,13 +15,15 @@ import ( "sync" "time" + "github.com/RomiChan/syncx" "github.com/pkg/errors" "github.com/tidwall/gjson" "github.com/Mrs4s/go-cqhttp/internal/base" ) -var client = newcli(time.Second * 15) +var client = newClient(time.Second * 15) +var clients syncx.Map[time.Duration, *http.Client] var clienth2 = &http.Client{ Transport: &http.Transport{ @@ -37,7 +39,7 @@ var clienth2 = &http.Client{ Timeout: time.Second * 15, } -func newcli(t time.Duration) *http.Client { +func newClient(t time.Duration) *http.Client { return &http.Client{ Transport: &http.Transport{ Proxy: func(request *http.Request) (*url.URL, error) { @@ -62,7 +64,13 @@ const UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 // WithTimeout get a download instance with timeout t func (r Request) WithTimeout(t time.Duration) *Request { - r.custcli = newcli(t) + if c, ok := clients.Load(t); ok { + r.custcli = c + } else { + c := newClient(t) + clients.Store(t, c) + r.custcli = c + } return &r } @@ -137,6 +145,7 @@ func (r Request) Bytes() ([]byte, error) { return nil, err } defer rd.Close() + defer r.client().CloseIdleConnections() return io.ReadAll(rd) } @@ -147,6 +156,7 @@ func (r Request) JSON() (gjson.Result, error) { return gjson.Result{}, err } defer rd.Close() + defer r.client().CloseIdleConnections() var sb strings.Builder _, err = io.Copy(&sb, rd) @@ -174,6 +184,7 @@ func (r Request) WriteToFile(path string) error { return err } defer rd.Close() + defer r.client().CloseIdleConnections() return writeToFile(rd, path) } @@ -183,6 +194,7 @@ func (r Request) WriteToFileMultiThreading(path string, thread int) error { return r.WriteToFile(path) } + defer r.client().CloseIdleConnections() limit := r.Limit type BlockMetaData struct { BeginOffset int64 diff --git a/modules/config/config.go b/modules/config/config.go index 4bfbc18c7..8feb981a2 100644 --- a/modules/config/config.go +++ b/modules/config/config.go @@ -28,20 +28,28 @@ type Reconnect struct { // Account 账号配置 type Account struct { - Uin int64 `yaml:"uin"` - Password string `yaml:"password"` - Encrypt bool `yaml:"encrypt"` - Status int `yaml:"status"` - ReLogin *Reconnect `yaml:"relogin"` - UseSSOAddress bool `yaml:"use-sso-address"` - AllowTempSession bool `yaml:"allow-temp-session"` - SignServer string `yaml:"sign-server"` - SignServerBearer string `yaml:"sign-server-bearer"` - Key string `yaml:"key"` - IsBelow110 bool `yaml:"is-below-110"` - AutoRegister bool `yaml:"auto-register"` - AutoRefreshToken bool `yaml:"auto-refresh-token"` - RefreshInterval int64 `yaml:"refresh-interval"` + Uin int64 `yaml:"uin"` + Password string `yaml:"password"` + Encrypt bool `yaml:"encrypt"` + Status int `yaml:"status"` + ReLogin *Reconnect `yaml:"relogin"` + UseSSOAddress bool `yaml:"use-sso-address"` + AllowTempSession bool `yaml:"allow-temp-session"` + SignServers []SignServer `yaml:"sign-servers"` + RuleChangeSignServer int `yaml:"rule-change-sign-server"` + MaxCheckCount uint `yaml:"max-check-count"` + SignServerTimeout uint `yaml:"sign-server-timeout"` + IsBelow110 bool `yaml:"is-below-110"` + AutoRegister bool `yaml:"auto-register"` + AutoRefreshToken bool `yaml:"auto-refresh-token"` + RefreshInterval int64 `yaml:"refresh-interval"` +} + +// SignServer 签名服务器 +type SignServer struct { + URL string `yaml:"url"` + Key string `yaml:"key"` + Authorization string `yaml:"authorization"` } // Config 总配置文件 @@ -64,7 +72,6 @@ type Config struct { SkipMimeScan bool `yaml:"skip-mime-scan"` ConvertWebpImage bool `yaml:"convert-webp-image"` HTTPTimeout int `yaml:"http-timeout"` - SignServerTimeout int `yaml:"sign-server-timeout"` } `yaml:"message"` Output struct { diff --git a/modules/config/default_config.yml b/modules/config/default_config.yml index 5acb845f4..66c25e6f6 100644 --- a/modules/config/default_config.yml +++ b/modules/config/default_config.yml @@ -16,26 +16,49 @@ account: # 账号相关 # 是否允许发送临时会话消息 allow-temp-session: false - # 数据包的签名服务器 + # 数据包的签名服务器列表,第一个作为主签名服务器,后续作为备用 # 兼容 https://github.com/fuqiuluo/unidbg-fetch-qsign - # 如果遇到 登录 45 错误, 或者发送信息风控的话需要填入一个服务器 + # 如果遇到 登录 45 错误, 或者发送信息风控的话需要填入一个或多个服务器 + # 不建议设置过多,设置主备各一个即可,超过 5 个只会取前五个 # 示例: - # sign-server: 'http://127.0.0.1:8080' # 本地签名服务器 - # sign-server: 'https://signserver.example.com' # 线上签名服务器 + # sign-servers: + # - url: 'http://127.0.0.1:8080' # 本地签名服务器 + # key: "114514" # 相应 key + # authorization: "-" # authorization 内容, 依服务端设置 + # - url: 'https://signserver.example.com' # 线上签名服务器 + # key: "114514" + # authorization: "-" + # ... + # # 服务器可使用docker在本地搭建或者使用他人开放的服务 - sign-server: '-' - # 签名服务器认证 Bearer Token - # 使用开放的服务可能需要提供此 Token 进行认证 - sign-server-bearer: '-' + sign-servers: + - url: '-' # 主签名服务器地址, 必填 + key: '114514' # 签名服务器所需要的apikey, 如果签名服务器的版本在1.1.0及以下则此项无效 + authorization: '-' # authorization 内容, 依服务端设置,如 'Bearer xxxx' + - url: '-' # 备用 + key: '114514' + authorization: '-' + + # 判断签名服务不可用(需要切换)的额外规则 + # 0: 不设置 (此时仅在请求无法返回结果时判定为不可用) + # 1: 在获取到的 sign 为空 (若选此建议关闭 auto-register,一般为实例未注册但是请求签名的情况) + # 2: 在获取到的 sign 或 token 为空(若选此建议关闭 auto-refresh-token ) + rule-change-sign-server: 1 + + # 连续寻找可用签名服务器最大尝试次数 + # 为 0 时会在连续 3 次没有找到可用签名服务器后保持使用主签名服务器,不再尝试进行切换备用 + # 否则会在达到指定次数后 **退出** 主程序 + max-check-count: 0 + # 签名服务请求超时时间(s) + sign-server-timeout: 60 # 如果签名服务器的版本在1.1.0及以下, 请将下面的参数改成true + # 建议使用 1.1.6 以上版本,低版本普遍半个月冻结一次 is-below-110: false - # 签名服务器所需要的apikey, 如果签名服务器的版本在1.1.0及以下则此项无效 - # 本地部署的默认为114514 - key: '114514' # 在实例可能丢失(获取到的签名为空)时是否尝试重新注册 # 为 true 时,在签名服务不可用时可能每次发消息都会尝试重新注册并签名。 # 为 false 时,将不会自动注册实例,在签名服务器重启或实例被销毁后需要重启 go-cqhttp 以获取实例 # 否则后续消息将不会正常签名。关闭此项后可以考虑开启签名服务器端 auto_register 避免需要重启 + # 由于实现问题,当前建议关闭此项,推荐开启签名服务器的自动注册实例 auto-register: false # 是否在 token 过期后立即自动刷新签名 token(在需要签名时才会检测到,主要防止 token 意外丢失) # 独立于定时刷新 @@ -75,8 +98,6 @@ message: convert-webp-image: false # download 超时时间(s) http-timeout: 15 - # 签名服务超时时间(s) - sign-server-timeout: 60 output: # 日志等级 trace,debug,info,warn,error diff --git a/server/websocket.go b/server/websocket.go index baaa471b1..b2b765c16 100644 --- a/server/websocket.go +++ b/server/websocket.go @@ -71,7 +71,7 @@ func (c *wsConn) Close() error { } var upgrader = websocket.Upgrader{ - CheckOrigin: func(r *http.Request) bool { + CheckOrigin: func(_ *http.Request) bool { return true }, }