From 1e42b2c45072bffef14b30aa6919b45d42d8c55e Mon Sep 17 00:00:00 2001 From: Mrs4s Date: Mon, 3 Apr 2023 20:26:43 +0800 Subject: [PATCH 01/10] feat: login error message --- cmd/gocq/login.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/cmd/gocq/login.go b/cmd/gocq/login.go index 9c0b826..9e904ce 100644 --- a/cmd/gocq/login.go +++ b/cmd/gocq/login.go @@ -218,6 +218,15 @@ func loginResponseProcessor(res *client.LoginResponse) error { case client.OtherLoginError, client.UnknownLoginError, client.TooManySMSRequestError: msg := res.ErrorMessage log.Warnf("登录失败: %v Code: %v", msg, res.Code) + switch res.Code { + case 235: + log.Warnf("设备信息被封禁, 请删除 device.json 后重试.") + case 237: + log.Warnf("登录过于频繁, 请在手机QQ登录并根据提示完成认证后等一段时间重试") + case 45: // 在提供 t544 后还是出现45错误是需要强行升级到最新客户端或被限制非常用设备 + log.Warnf("你的账号涉嫌违规被限制在非常用设备登录, 请在手机QQ登录并根据提示完成认证") + log.Warnf("或使用 -update-protocol 升级到最新协议后重试") + } if res.Code == 235 { log.Warnf("请删除 device.json 后重试.") } From 637d46f282f8ba44d07e07f5d1968dfc3c9a37d4 Mon Sep 17 00:00:00 2001 From: Mrs4s Date: Mon, 3 Apr 2023 20:28:25 +0800 Subject: [PATCH 02/10] rf: remove useless code --- cmd/gocq/login.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/cmd/gocq/login.go b/cmd/gocq/login.go index 9e904ce..a8c801b 100644 --- a/cmd/gocq/login.go +++ b/cmd/gocq/login.go @@ -227,9 +227,6 @@ func loginResponseProcessor(res *client.LoginResponse) error { log.Warnf("你的账号涉嫌违规被限制在非常用设备登录, 请在手机QQ登录并根据提示完成认证") log.Warnf("或使用 -update-protocol 升级到最新协议后重试") } - if res.Code == 235 { - log.Warnf("请删除 device.json 后重试.") - } log.Infof("按 Enter 继续....") readLine() os.Exit(0) From 7b2d1fd573ead7e88545d4e2e1681f36617d4fc6 Mon Sep 17 00:00:00 2001 From: Mrs4s Date: Wed, 5 Apr 2023 01:35:05 +0800 Subject: [PATCH 03/10] rf: remove sse2 check --- internal/encryption/t544/cpuid_amd64.go | 10 ---------- internal/encryption/t544/cpuid_amd64.s | 15 --------------- internal/encryption/t544/t544.go | 6 ++---- 3 files changed, 2 insertions(+), 29 deletions(-) delete mode 100644 internal/encryption/t544/cpuid_amd64.go delete mode 100644 internal/encryption/t544/cpuid_amd64.s diff --git a/internal/encryption/t544/cpuid_amd64.go b/internal/encryption/t544/cpuid_amd64.go deleted file mode 100644 index a8e21a9..0000000 --- a/internal/encryption/t544/cpuid_amd64.go +++ /dev/null @@ -1,10 +0,0 @@ -//go:build amd64 - -package t544 - -func cpuid(op uint32) (eax, ebx, ecx, edx uint32) - -var canusesse2 = func() bool { - _, _, _, d := cpuid(1) - return d&(1<<26) > 0 -}() diff --git a/internal/encryption/t544/cpuid_amd64.s b/internal/encryption/t544/cpuid_amd64.s deleted file mode 100644 index 98f50a2..0000000 --- a/internal/encryption/t544/cpuid_amd64.s +++ /dev/null @@ -1,15 +0,0 @@ -//go:build amd64 -// +build amd64 - -// Copyright (c) 2015 Klaus Post, released under MIT License. See LICENSE file. - -// func cpuid(op uint32) (eax, ebx, ecx, edx uint32) -TEXT ·cpuid(SB), 7, $0 - XORQ CX, CX - MOVL op+0(FP), AX - CPUID - MOVL AX, eax+8(FP) - MOVL BX, ebx+12(FP) - MOVL CX, ecx+16(FP) - MOVL DX, edx+20(FP) - RET diff --git a/internal/encryption/t544/t544.go b/internal/encryption/t544/t544.go index 9cb99f1..321fcb1 100644 --- a/internal/encryption/t544/t544.go +++ b/internal/encryption/t544/t544.go @@ -24,10 +24,8 @@ var ( ) func init() { - if canusesse2 { - encryption.T544Signer["8.9.35.10440"] = sign - encryption.T544Signer["8.9.38.10545"] = sign - } + encryption.T544Signer["8.9.35.10440"] = sign + encryption.T544Signer["8.9.38.10545"] = sign } // sign t544 algorithm From 13325634c04f06745589c3d552ea1077b5219f37 Mon Sep 17 00:00:00 2001 From: wdvxdr Date: Sat, 8 Apr 2023 11:34:19 +0800 Subject: [PATCH 04/10] make lint happy --- cmd/gocq/login.go | 7 ++-- cmd/gocq/main.go | 82 ++++++++++++++++++-------------------- coolq/api_v12.go | 2 +- coolq/event.go | 16 ++++---- internal/msg/parse_test.go | 2 +- 5 files changed, 52 insertions(+), 57 deletions(-) diff --git a/cmd/gocq/login.go b/cmd/gocq/login.go index a8c801b..404cf89 100644 --- a/cmd/gocq/login.go +++ b/cmd/gocq/login.go @@ -15,18 +15,17 @@ import ( "github.com/Mrs4s/MiraiGo/client" "github.com/Mrs4s/MiraiGo/utils" "github.com/Mrs4s/MiraiGo/wrapper" - "github.com/Mrs4s/go-cqhttp/internal/encryption" - _ "github.com/Mrs4s/go-cqhttp/internal/encryption/t544" "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/internal/base" - "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/internal/encryption" + _ "github.com/Mrs4s/go-cqhttp/internal/encryption/t544" // side effect ) var console = bufio.NewReader(os.Stdin) diff --git a/cmd/gocq/main.go b/cmd/gocq/main.go index efd6479..4463fbf 100644 --- a/cmd/gocq/main.go +++ b/cmd/gocq/main.go @@ -22,14 +22,13 @@ import ( "golang.org/x/crypto/pbkdf2" "golang.org/x/term" - "github.com/Mrs4s/go-cqhttp/internal/download" - "github.com/Mrs4s/go-cqhttp/coolq" "github.com/Mrs4s/go-cqhttp/db" "github.com/Mrs4s/go-cqhttp/global" "github.com/Mrs4s/go-cqhttp/global/terminal" "github.com/Mrs4s/go-cqhttp/internal/base" "github.com/Mrs4s/go-cqhttp/internal/cache" + "github.com/Mrs4s/go-cqhttp/internal/download" "github.com/Mrs4s/go-cqhttp/internal/selfdiagnosis" "github.com/Mrs4s/go-cqhttp/internal/selfupdate" "github.com/Mrs4s/go-cqhttp/modules/servers" @@ -168,51 +167,48 @@ func LoginInteract() { if !global.PathExists("password.encrypt") { if base.Account.Password == "" { log.Error("无法进行加密,请在配置文件中的添加密码后重新启动.") - readLine() - os.Exit(0) + } else { + log.Infof("密码加密已启用, 请输入Key对密码进行加密: (Enter 提交)") + byteKey, _ = term.ReadPassword(int(os.Stdin.Fd())) + base.PasswordHash = md5.Sum([]byte(base.Account.Password)) + _ = os.WriteFile("password.encrypt", []byte(PasswordHashEncrypt(base.PasswordHash[:], byteKey)), 0o644) + log.Info("密码已加密,为了您的账号安全,请删除配置文件中的密码后重新启动.") } - log.Infof("密码加密已启用, 请输入Key对密码进行加密: (Enter 提交)") - byteKey, _ = term.ReadPassword(int(os.Stdin.Fd())) - base.PasswordHash = md5.Sum([]byte(base.Account.Password)) - _ = os.WriteFile("password.encrypt", []byte(PasswordHashEncrypt(base.PasswordHash[:], byteKey)), 0o644) - log.Info("密码已加密,为了您的账号安全,请删除配置文件中的密码后重新启动.") readLine() os.Exit(0) - } else { - if base.Account.Password != "" { - log.Error("密码已加密,为了您的账号安全,请删除配置文件中的密码后重新启动.") - readLine() - os.Exit(0) - } - - if len(byteKey) == 0 { - log.Infof("密码加密已启用, 请输入Key对密码进行解密以继续: (Enter 提交)") - cancel := make(chan struct{}, 1) - state, _ := term.GetState(int(os.Stdin.Fd())) - go func() { - select { - case <-cancel: - return - case <-time.After(time.Second * 45): - log.Infof("解密key输入超时") - time.Sleep(3 * time.Second) - _ = term.Restore(int(os.Stdin.Fd()), state) - os.Exit(0) - } - }() - byteKey, _ = term.ReadPassword(int(os.Stdin.Fd())) - cancel <- struct{}{} - } else { - log.Infof("密码加密已启用, 使用运行时传递的参数进行解密,按 Ctrl+C 取消.") - } - - encrypt, _ := os.ReadFile("password.encrypt") - ph, err := PasswordHashDecrypt(string(encrypt), byteKey) - if err != nil { - log.Fatalf("加密存储的密码损坏,请尝试重新配置密码") - } - copy(base.PasswordHash[:], ph) } + if base.Account.Password != "" { + log.Error("密码已加密,为了您的账号安全,请删除配置文件中的密码后重新启动.") + readLine() + os.Exit(0) + } + if len(byteKey) == 0 { + log.Infof("密码加密已启用, 请输入Key对密码进行解密以继续: (Enter 提交)") + cancel := make(chan struct{}, 1) + state, _ := term.GetState(int(os.Stdin.Fd())) + go func() { + select { + case <-cancel: + return + case <-time.After(time.Second * 45): + log.Infof("解密key输入超时") + time.Sleep(3 * time.Second) + _ = term.Restore(int(os.Stdin.Fd()), state) + os.Exit(0) + } + }() + byteKey, _ = term.ReadPassword(int(os.Stdin.Fd())) + cancel <- struct{}{} + } else { + log.Infof("密码加密已启用, 使用运行时传递的参数进行解密,按 Ctrl+C 取消.") + } + + encrypt, _ := os.ReadFile("password.encrypt") + ph, err := PasswordHashDecrypt(string(encrypt), byteKey) + if err != nil { + log.Fatalf("加密存储的密码损坏,请尝试重新配置密码") + } + copy(base.PasswordHash[:], ph) } else if len(base.Account.Password) > 0 { base.PasswordHash = md5.Sum([]byte(base.Account.Password)) } diff --git a/coolq/api_v12.go b/coolq/api_v12.go index 21c8835..cbda8ed 100644 --- a/coolq/api_v12.go +++ b/coolq/api_v12.go @@ -28,7 +28,7 @@ func (bot *CQBot) CQGetVersion() global.MSG { // // @route12(send_message) // @rename(m->message) -func (bot *CQBot) CQSendMessageV12(groupID, userID, detailType string, m gjson.Result) global.MSG { +func (bot *CQBot) CQSendMessageV12(groupID, userID, detailType string, m gjson.Result) global.MSG { // nolint // TODO: implement return OK(nil) } diff --git a/coolq/event.go b/coolq/event.go index 5fa4b85..605ea3e 100644 --- a/coolq/event.go +++ b/coolq/event.go @@ -136,7 +136,7 @@ func (bot *CQBot) groupMessageEvent(c *client.QQClient, m *message.GroupMessage) bot.dispatch(gm) } -func (bot *CQBot) tempMessageEvent(c *client.QQClient, e *client.TempMessageEvent) { +func (bot *CQBot) tempMessageEvent(_ *client.QQClient, e *client.TempMessageEvent) { m := e.Message bot.checkMedia(m.Elements, m.Sender.Uin) source := message.Source{ @@ -491,7 +491,7 @@ func (bot *CQBot) leaveGroupEvent(c *client.QQClient, e *client.GroupLeaveEvent) bot.dispatch(bot.groupDecrease(e.Group.Code, c.Uin, e.Operator)) } -func (bot *CQBot) memberPermissionChangedEvent(c *client.QQClient, e *client.MemberPermissionChangedEvent) { +func (bot *CQBot) memberPermissionChangedEvent(_ *client.QQClient, e *client.MemberPermissionChangedEvent) { st := "unset" if e.NewPermission == client.Administrator { st = "set" @@ -502,7 +502,7 @@ func (bot *CQBot) memberPermissionChangedEvent(c *client.QQClient, e *client.Mem }) } -func (bot *CQBot) memberCardUpdatedEvent(c *client.QQClient, e *client.MemberCardUpdatedEvent) { +func (bot *CQBot) memberCardUpdatedEvent(_ *client.QQClient, e *client.MemberCardUpdatedEvent) { log.Infof("群 %v 的 %v 更新了名片 %v -> %v", formatGroupName(e.Group), formatMemberName(e.Member), e.OldCard, e.Member.CardName) bot.dispatchEvent("notice/group_card", global.MSG{ "group_id": e.Group.Code, @@ -526,7 +526,7 @@ func (bot *CQBot) memberLeaveEvent(_ *client.QQClient, e *client.MemberLeaveGrou bot.dispatch(bot.groupDecrease(e.Group.Code, e.Member.Uin, e.Operator)) } -func (bot *CQBot) friendRequestEvent(c *client.QQClient, e *client.NewFriendRequest) { +func (bot *CQBot) friendRequestEvent(_ *client.QQClient, e *client.NewFriendRequest) { log.Infof("收到来自 %v(%v) 的好友请求: %v", e.RequesterNick, e.RequesterUin, e.Message) flag := strconv.FormatInt(e.RequestId, 10) bot.friendReqCache.Store(flag, e) @@ -537,7 +537,7 @@ func (bot *CQBot) friendRequestEvent(c *client.QQClient, e *client.NewFriendRequ }) } -func (bot *CQBot) friendAddedEvent(c *client.QQClient, e *client.NewFriendEvent) { +func (bot *CQBot) friendAddedEvent(_ *client.QQClient, e *client.NewFriendEvent) { log.Infof("添加了新好友: %v(%v)", e.Friend.Nickname, e.Friend.Uin) bot.tempSessionCache.Delete(e.Friend.Uin) bot.dispatchEvent("notice/friend_add", global.MSG{ @@ -545,7 +545,7 @@ func (bot *CQBot) friendAddedEvent(c *client.QQClient, e *client.NewFriendEvent) }) } -func (bot *CQBot) groupInvitedEvent(c *client.QQClient, e *client.GroupInvitedRequest) { +func (bot *CQBot) groupInvitedEvent(_ *client.QQClient, e *client.GroupInvitedRequest) { log.Infof("收到来自群 %v(%v) 内用户 %v(%v) 的加群邀请.", e.GroupName, e.GroupCode, e.InvitorNick, e.InvitorUin) flag := strconv.FormatInt(e.RequestId, 10) bot.dispatchEvent("request/group/invite", global.MSG{ @@ -557,7 +557,7 @@ func (bot *CQBot) groupInvitedEvent(c *client.QQClient, e *client.GroupInvitedRe }) } -func (bot *CQBot) groupJoinReqEvent(c *client.QQClient, e *client.UserJoinGroupRequest) { +func (bot *CQBot) groupJoinReqEvent(_ *client.QQClient, e *client.UserJoinGroupRequest) { log.Infof("群 %v(%v) 收到来自用户 %v(%v) 的加群请求.", e.GroupName, e.GroupCode, e.RequesterNick, e.RequesterUin) flag := strconv.FormatInt(e.RequestId, 10) bot.dispatchEvent("request/group/add", global.MSG{ @@ -569,7 +569,7 @@ func (bot *CQBot) groupJoinReqEvent(c *client.QQClient, e *client.UserJoinGroupR }) } -func (bot *CQBot) otherClientStatusChangedEvent(c *client.QQClient, e *client.OtherClientStatusChangedEvent) { +func (bot *CQBot) otherClientStatusChangedEvent(_ *client.QQClient, e *client.OtherClientStatusChangedEvent) { if e.Online { log.Infof("Bot 账号在客户端 %v (%v) 登录.", e.Client.DeviceName, e.Client.DeviceKind) } else { diff --git a/internal/msg/parse_test.go b/internal/msg/parse_test.go index 21998c7..d11c3b7 100644 --- a/internal/msg/parse_test.go +++ b/internal/msg/parse_test.go @@ -10,7 +10,7 @@ import ( "github.com/tidwall/gjson" ) -func TestParseString(t *testing.T) { +func TestParseString(_ *testing.T) { // TODO: add more text for _, v := range ParseString(`[CQ:face,id=115,text=111][CQ:face,id=217]] [CQ:text,text=123] [`) { fmt.Println(v) From 54995fc1018b1659863a445c78db8dcb40961220 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=BA=90=E6=96=87=E9=9B=A8?= <41315874+fumiama@users.noreply.github.com> Date: Sat, 8 Apr 2023 12:05:45 +0800 Subject: [PATCH 05/10] =?UTF-8?q?fix:=20=E5=B0=9D=E8=AF=95=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=20#2070=20(#2071)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- internal/encryption/t544/encryption_amd64.s | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/encryption/t544/encryption_amd64.s b/internal/encryption/t544/encryption_amd64.s index 6460c97..5ad7b98 100644 --- a/internal/encryption/t544/encryption_amd64.s +++ b/internal/encryption/t544/encryption_amd64.s @@ -244,11 +244,11 @@ TEXT ·sub_d(SB), NOSPLIT, $16-32 MOVQ SI, DI ADDQ $15, DI MOVB $16, CX - STD lop: LEAQ -1(CX), AX XLAT MOVBLZX in-16(SP)(AX*1), AX + STD STOSB LOOP lop RET From 55cb80dccce05885f1242fd4379a8c9cd35eeb7a Mon Sep 17 00:00:00 2001 From: wdvxdr Date: Sat, 8 Apr 2023 12:09:58 +0800 Subject: [PATCH 06/10] onebot: pick Attr, Value from log/slog [wip] --- pkg/onebot/attr.go | 78 +++++++++ pkg/onebot/kind_string.go | 31 ++++ pkg/onebot/value.go | 354 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 463 insertions(+) create mode 100644 pkg/onebot/attr.go create mode 100644 pkg/onebot/kind_string.go create mode 100644 pkg/onebot/value.go diff --git a/pkg/onebot/attr.go b/pkg/onebot/attr.go new file mode 100644 index 0000000..485fa2f --- /dev/null +++ b/pkg/onebot/attr.go @@ -0,0 +1,78 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package onebot + +import ( + "time" +) + +// An Attr is a key-value pair. +type Attr struct { + Key string + Value Value +} + +// String returns an Attr for a string value. +func String(key, value string) Attr { + return Attr{key, StringValue(value)} +} + +// Int64 returns an Attr for an int64. +func Int64(key string, value int64) Attr { + return Attr{key, Int64Value(value)} +} + +// Int converts an int to an int64 and returns +// an Attr with that value. +func Int(key string, value int) Attr { + return Int64(key, int64(value)) +} + +// Uint64 returns an Attr for a uint64. +func Uint64(key string, v uint64) Attr { + return Attr{key, Uint64Value(v)} +} + +// Float64 returns an Attr for a floating-point number. +func Float64(key string, v float64) Attr { + return Attr{key, Float64Value(v)} +} + +// Bool returns an Attr for a bool. +func Bool(key string, v bool) Attr { + return Attr{key, BoolValue(v)} +} + +// Time returns an Attr for a time.Time. +// It discards the monotonic portion. +func Time(key string, v time.Time) Attr { + return Attr{key, TimeValue(v)} +} + +// Duration returns an Attr for a time.Duration. +func Duration(key string, v time.Duration) Attr { + return Attr{key, DurationValue(v)} +} + +// Group returns an Attr for a Group Value. +// The caller must not subsequently mutate the +// argument slice. +// +// Use Group to collect several Attrs under a single +// key on a log line, or as the result of LogValue +// in order to log a single value as multiple Attrs. +func Group(key string, as ...Attr) Attr { + return Attr{key, GroupValue(as...)} +} + +// Any returns an Attr for the supplied value. +// See [Value.AnyValue] for how values are treated. +func Any(key string, value any) Attr { + return Attr{key, AnyValue(value)} +} + +func (a Attr) String() string { + return a.Key + "=" + a.Value.String() +} diff --git a/pkg/onebot/kind_string.go b/pkg/onebot/kind_string.go new file mode 100644 index 0000000..7e04ad4 --- /dev/null +++ b/pkg/onebot/kind_string.go @@ -0,0 +1,31 @@ +// Code generated by "stringer -type=Kind -trimprefix=Kind"; DO NOT EDIT. + +package onebot + +import "strconv" + +func _() { + // An "invalid array index" compiler error signifies that the constant values have changed. + // Re-run the stringer command to generate them again. + var x [1]struct{} + _ = x[KindAny-0] + _ = x[KindBool-1] + _ = x[KindDuration-2] + _ = x[KindFloat64-3] + _ = x[KindInt64-4] + _ = x[KindString-5] + _ = x[KindTime-6] + _ = x[KindUint64-7] + _ = x[KindGroup-8] +} + +const _Kind_name = "AnyBoolDurationFloat64Int64StringTimeUint64Group" + +var _Kind_index = [...]uint8{0, 3, 7, 15, 22, 27, 33, 37, 43, 48} + +func (i Kind) String() string { + if i < 0 || i >= Kind(len(_Kind_index)-1) { + return "Kind(" + strconv.FormatInt(int64(i), 10) + ")" + } + return _Kind_name[_Kind_index[i]:_Kind_index[i+1]] +} diff --git a/pkg/onebot/value.go b/pkg/onebot/value.go new file mode 100644 index 0000000..6192ef8 --- /dev/null +++ b/pkg/onebot/value.go @@ -0,0 +1,354 @@ +// Copyright 2022 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package onebot + +import ( + "fmt" + "math" + "strconv" + "time" + "unsafe" +) + +// A Value can represent any Go value, but unlike type any, +// it can represent most small values without an allocation. +// The zero Value corresponds to nil. +type Value struct { + _ [0]func() // disallow == + num uint64 // hold number value + any any // hold Kind or other value +} + +type ( + stringptr *byte // used in Value.any when the Value is a string + groupptr *Attr // used in Value.any when the Value is a []Attr +) + +//go:generate stringer -type=Kind -trimprefix=Kind + +// Kind is the kind of Value. +type Kind int + +const ( + KindAny Kind = iota + KindBool + KindDuration + KindFloat64 + KindInt64 + KindString + KindTime + KindUint64 + KindGroup +) + +// Unexported version of Kind, just so we can store Kinds in Values. +// (No user-provided value has this type.) +type kind Kind + +// Kind returns v's Kind. +func (v Value) Kind() Kind { + switch x := v.any.(type) { + case Kind: + return x + case stringptr: + return KindString + case timeLocation: + return KindTime + case groupptr: + return KindGroup + case kind: // a kind is just a wrapper for a Kind + return KindAny + default: + return KindAny + } +} + +//////////////// Constructors + +// StringValue returns a new Value for a string. +func StringValue(value string) Value { + return Value{num: uint64(len(value)), any: stringptr(unsafe.StringData(value))} +} + +// IntValue returns a Value for an int. +func IntValue(v int) Value { + return Int64Value(int64(v)) +} + +// Int64Value returns a Value for an int64. +func Int64Value(v int64) Value { + return Value{num: uint64(v), any: KindInt64} +} + +// Uint64Value returns a Value for a uint64. +func Uint64Value(v uint64) Value { + return Value{num: v, any: KindUint64} +} + +// Float64Value returns a Value for a floating-point number. +func Float64Value(v float64) Value { + return Value{num: math.Float64bits(v), any: KindFloat64} +} + +// BoolValue returns a Value for a bool. +func BoolValue(v bool) Value { + u := uint64(0) + if v { + u = 1 + } + return Value{num: u, any: KindBool} +} + +// Unexported version of *time.Location, just so we can store *time.Locations in +// Values. (No user-provided value has this type.) +type timeLocation *time.Location + +// TimeValue returns a Value for a time.Time. +// It discards the monotonic portion. +func TimeValue(v time.Time) Value { + if v.IsZero() { + // UnixNano on the zero time is undefined, so represent the zero time + // with a nil *time.Location instead. time.Time.Location method never + // returns nil, so a Value with any == timeLocation(nil) cannot be + // mistaken for any other Value, time.Time or otherwise. + return Value{any: timeLocation(nil)} + } + return Value{num: uint64(v.UnixNano()), any: timeLocation(v.Location())} +} + +// DurationValue returns a Value for a time.Duration. +func DurationValue(v time.Duration) Value { + return Value{num: uint64(v.Nanoseconds()), any: KindDuration} +} + +// GroupValue returns a new Value for a list of Attrs. +// The caller must not subsequently mutate the argument slice. +func GroupValue(as ...Attr) Value { + return Value{num: uint64(len(as)), any: groupptr(unsafe.SliceData(as))} +} + +// AnyValue returns a Value for the supplied value. +// +// If the supplied value is of type Value, it is returned +// unmodified. +// +// Given a value of one of Go's predeclared string, bool, or +// (non-complex) numeric types, AnyValue returns a Value of kind +// String, Bool, Uint64, Int64, or Float64. The width of the +// original numeric type is not preserved. +// +// Given a time.Time or time.Duration value, AnyValue returns a Value of kind +// KindTime or KindDuration. The monotonic time is not preserved. +// +// For nil, or values of all other types, including named types whose +// underlying type is numeric, AnyValue returns a value of kind KindAny. +func AnyValue(v any) Value { + switch v := v.(type) { + case string: + return StringValue(v) + case int: + return Int64Value(int64(v)) + case uint: + return Uint64Value(uint64(v)) + case int64: + return Int64Value(v) + case uint64: + return Uint64Value(v) + case bool: + return BoolValue(v) + case time.Duration: + return DurationValue(v) + case time.Time: + return TimeValue(v) + case uint8: + return Uint64Value(uint64(v)) + case uint16: + return Uint64Value(uint64(v)) + case uint32: + return Uint64Value(uint64(v)) + case uintptr: + return Uint64Value(uint64(v)) + case int8: + return Int64Value(int64(v)) + case int16: + return Int64Value(int64(v)) + case int32: + return Int64Value(int64(v)) + case float64: + return Float64Value(v) + case float32: + return Float64Value(float64(v)) + case []Attr: + return GroupValue(v...) + case Kind: + return Value{any: kind(v)} + case Value: + return v + default: + return Value{any: v} + } +} + +//////////////// Accessors + +// Any returns v's value as an any. +func (v Value) Any() any { + switch v.Kind() { + case KindAny: + if k, ok := v.any.(kind); ok { + return Kind(k) + } + return v.any + case KindGroup: + return v.group() + case KindInt64: + return int64(v.num) + case KindUint64: + return v.num + case KindFloat64: + return v.float() + case KindString: + return v.str() + case KindBool: + return v.bool() + case KindDuration: + return v.duration() + case KindTime: + return v.time() + default: + panic(fmt.Sprintf("bad kind: %s", v.Kind())) + } +} + +// String returns Value's value as a string, formatted like fmt.Sprint. Unlike +// the methods Int64, Float64, and so on, which panic if v is of the +// wrong kind, String never panics. +func (v Value) String() string { + if sp, ok := v.any.(stringptr); ok { + return unsafe.String(sp, v.num) + } + var buf []byte + return string(v.append(buf)) +} + +func (v Value) str() string { + return unsafe.String(v.any.(stringptr), v.num) +} + +// Int64 returns v's value as an int64. It panics +// if v is not a signed integer. +func (v Value) Int64() int64 { + if g, w := v.Kind(), KindInt64; g != w { + panic(fmt.Sprintf("Value kind is %s, not %s", g, w)) + } + return int64(v.num) +} + +// Uint64 returns v's value as a uint64. It panics +// if v is not an unsigned integer. +func (v Value) Uint64() uint64 { + if g, w := v.Kind(), KindUint64; g != w { + panic(fmt.Sprintf("Value kind is %s, not %s", g, w)) + } + return v.num +} + +// Bool returns v's value as a bool. It panics +// if v is not a bool. +func (v Value) Bool() bool { + if g, w := v.Kind(), KindBool; g != w { + panic(fmt.Sprintf("Value kind is %s, not %s", g, w)) + } + return v.bool() +} + +func (v Value) bool() bool { + return v.num == 1 +} + +// Duration returns v's value as a time.Duration. It panics +// if v is not a time.Duration. +func (v Value) Duration() time.Duration { + if g, w := v.Kind(), KindDuration; g != w { + panic(fmt.Sprintf("Value kind is %s, not %s", g, w)) + } + + return v.duration() +} + +func (v Value) duration() time.Duration { + return time.Duration(int64(v.num)) +} + +// Float64 returns v's value as a float64. It panics +// if v is not a float64. +func (v Value) Float64() float64 { + if g, w := v.Kind(), KindFloat64; g != w { + panic(fmt.Sprintf("Value kind is %s, not %s", g, w)) + } + + return v.float() +} + +func (v Value) float() float64 { + return math.Float64frombits(v.num) +} + +// Time returns v's value as a time.Time. It panics +// if v is not a time.Time. +func (v Value) Time() time.Time { + if g, w := v.Kind(), KindTime; g != w { + panic(fmt.Sprintf("Value kind is %s, not %s", g, w)) + } + return v.time() +} + +func (v Value) time() time.Time { + loc := v.any.(timeLocation) + if loc == nil { + return time.Time{} + } + return time.Unix(0, int64(v.num)).In(loc) +} + +// Group returns v's value as a []Attr. +// It panics if v's Kind is not KindGroup. +func (v Value) Group() []Attr { + if sp, ok := v.any.(groupptr); ok { + return unsafe.Slice(sp, v.num) + } + panic("Group: bad kind") +} + +func (v Value) group() []Attr { + return unsafe.Slice((*Attr)(v.any.(groupptr)), v.num) +} + +// append appends a text representation of v to dst. +// v is formatted as with fmt.Sprint. +func (v Value) append(dst []byte) []byte { + switch v.Kind() { + case KindString: + return append(dst, v.str()...) + case KindInt64: + return strconv.AppendInt(dst, int64(v.num), 10) + case KindUint64: + return strconv.AppendUint(dst, v.num, 10) + case KindFloat64: + return strconv.AppendFloat(dst, v.float(), 'g', -1, 64) + case KindBool: + return strconv.AppendBool(dst, v.bool()) + case KindDuration: + return append(dst, v.duration().String()...) + case KindTime: + return append(dst, v.time().String()...) + case KindGroup: + return fmt.Append(dst, v.group()) + case KindAny: + return fmt.Append(dst, v.any) + default: + panic(fmt.Sprintf("bad kind: %s", v.Kind())) + } +} From 0b90074a48b4de2f447fe5025e9c4fb18e64df52 Mon Sep 17 00:00:00 2001 From: Mrs4s Date: Sat, 8 Apr 2023 17:08:53 +0800 Subject: [PATCH 07/10] feat: http timeout setting --- cmd/gocq/main.go | 2 +- internal/base/flag.go | 2 ++ internal/download/download.go | 9 ++++++++- modules/config/config.go | 1 + 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/cmd/gocq/main.go b/cmd/gocq/main.go index 4463fbf..2e6c85a 100644 --- a/cmd/gocq/main.go +++ b/cmd/gocq/main.go @@ -364,6 +364,7 @@ func LoginInteract() { }) saveToken() cli.AllowSlider = true + download.SetGlobalTimeout(time.Duration(base.HTTPTimeout) * time.Second) // 在登录完成后设置, 防止在堵塞协议更新 log.Infof("登录成功 欢迎使用: %v", cli.Nickname) log.Info("开始加载好友列表...") global.Check(cli.ReloadFriendList(), true) @@ -375,7 +376,6 @@ func LoginInteract() { base.Account.Status = 0 } cli.SetOnlineStatus(allowStatus[base.Account.Status]) - servers.Run(coolq.NewQQBot(cli)) log.Info("资源初始化完成, 开始处理信息.") log.Info("アトリは、高性能ですから!") diff --git a/internal/base/flag.go b/internal/base/flag.go index 44e018c..b5b6ce5 100644 --- a/internal/base/flag.go +++ b/internal/base/flag.go @@ -39,6 +39,7 @@ var ( AllowTempSession bool // 是否允许发送临时会话信息 UpdateProtocol bool // 是否更新协议 SignServerOverwrite string // 使用特定的服务器进行签名 + HTTPTimeout int PostFormat string // 上报格式 string or array Proxy string // 存储 proxy_rewrite,用于设置代理 @@ -88,6 +89,7 @@ func Init() { ReportSelfMessage = conf.Message.ReportSelfMessage UseSSOAddress = conf.Account.UseSSOAddress AllowTempSession = conf.Account.AllowTempSession + HTTPTimeout = conf.Message.HTTPTimeout } { // others Proxy = conf.Message.ProxyRewrite diff --git a/internal/download/download.go b/internal/download/download.go index a7b7e06..7622e4c 100644 --- a/internal/download/download.go +++ b/internal/download/download.go @@ -33,7 +33,7 @@ var client = &http.Client{ MaxIdleConns: 0, MaxIdleConnsPerHost: 999, }, - Timeout: time.Second * 15, + Timeout: time.Second * 5, } // ErrOverSize 响应主体过大时返回此错误 @@ -42,6 +42,13 @@ var ErrOverSize = errors.New("oversize") // UserAgent HTTP请求时使用的UA const UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 Edg/87.0.664.66" +func SetGlobalTimeout(t time.Duration) { + if t == 0 { + t = time.Second * 10 + } + client.Timeout = t +} + // Request is a file download request type Request struct { Method string diff --git a/modules/config/config.go b/modules/config/config.go index 22d9879..512915c 100644 --- a/modules/config/config.go +++ b/modules/config/config.go @@ -56,6 +56,7 @@ type Config struct { ExtraReplyData bool `yaml:"extra-reply-data"` SkipMimeScan bool `yaml:"skip-mime-scan"` ConvertWebpImage bool `yaml:"convert-webp-image"` + HTTPTimeout int `yaml:"http-timeout"` } `yaml:"message"` Output struct { From 91b4394d9bffe0a4c7104c9120cbe5e8d11b6bc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=BA=90=E6=96=87=E9=9B=A8?= <41315874+fumiama@users.noreply.github.com> Date: Sun, 9 Apr 2023 17:25:57 +0800 Subject: [PATCH 08/10] optimize(t544): drop unsafe (#2076) Updates #2075 #2072 #2051 --- internal/encryption/t544/encryption.go | 2 +- internal/encryption/t544/encryption_amd64.s | 118 +++++++++++------- .../encryption/t544/encryption_generic.go | 7 +- internal/encryption/t544/t544.go | 10 +- internal/encryption/t544/t544_test.go | 22 ++++ 5 files changed, 104 insertions(+), 55 deletions(-) create mode 100755 internal/encryption/t544/t544_test.go diff --git a/internal/encryption/t544/encryption.go b/internal/encryption/t544/encryption.go index 75c91d2..89b09c0 100644 --- a/internal/encryption/t544/encryption.go +++ b/internal/encryption/t544/encryption.go @@ -50,4 +50,4 @@ func (c *state) init(key []byte, data []byte, counter uint64, nr uint8) { initState(c, key, data, counter) } -func sub_ad([]uint32) +func refreshState(c *state) diff --git a/internal/encryption/t544/encryption_amd64.s b/internal/encryption/t544/encryption_amd64.s index 5ad7b98..2460145 100644 --- a/internal/encryption/t544/encryption_amd64.s +++ b/internal/encryption/t544/encryption_amd64.s @@ -10,8 +10,8 @@ DATA LC0<>+12(SB)/4, $1797285236 GLOBL LC0<>(SB), NOPTR, $16 TEXT ·sub_a(SB), NOSPLIT, $0-48 - MOVQ ·a+0(FP), DI - MOVQ ·b+24(FP), CX + MOVQ a+0(FP), DI + MOVQ b+24(FP), CX MOVQ CX, DX MOVBLZX 3(CX), CX XORB CX, (DI) @@ -48,8 +48,8 @@ TEXT ·sub_a(SB), NOSPLIT, $0-48 RET TEXT ·sub_b(SB), NOSPLIT, $0-48 - MOVQ ·a+0(FP), DI - MOVQ ·b+24(FP), CX + MOVQ a+0(FP), DI + MOVQ b+24(FP), CX MOVQ CX, DX MOVBLZX 3(CX), CX XORB CX, (DI) @@ -87,8 +87,8 @@ TEXT ·sub_b(SB), NOSPLIT, $0-48 TEXT ·sub_c(SB), NOSPLIT, $0-32 - MOVQ ·a+0(FP), DI - MOVQ ·b+8(FP), SI + MOVQ a+0(FP), DI + MOVQ b+8(FP), SI MOVQ SI, AX MOVBLZX (SI), SI MOVL SI, CX @@ -236,26 +236,27 @@ TEXT ·sub_c(SB), NOSPLIT, $0-32 MOVB CX, 15(AX) RET -TEXT ·sub_d(SB), NOSPLIT, $16-32 - MOVQ ·t+0(FP), BX - MOVQ ·s+8(FP), SI - MOVOU (SI), X0 +TEXT ·sub_d(SB), NOSPLIT, $24-32 + MOVQ t+0(FP), BX + MOVQ s+8(FP), DI + MOVOU (DI), X0 MOVOU X0, in-16(SP) - MOVQ SI, DI + MOVQ $16, CX ADDQ $15, DI - MOVB $16, CX + PUSHFQ + STD lop: LEAQ -1(CX), AX XLAT - MOVBLZX in-16(SP)(AX*1), AX - STD - STOSB + LEAQ in-16(SP)(AX*1), SI + MOVSB LOOP lop + POPFQ RET TEXT ·sub_e(SB), NOSPLIT, $0-32 - MOVQ ·a+0(FP), DI - MOVQ ·n+8(FP), SI + MOVQ a+0(FP), DI + MOVQ n+8(FP), SI MOVQ $4, AX lop: MOVBQZX -4(SI)(AX*4), DX @@ -295,9 +296,9 @@ lop: JNZ lop RET -TEXT sub_ab(SB), NOSPLIT, $0-24 - MOVQ ·s+0(FP), DI - MOVQ ·w+8(FP), SI +TEXT sub_ab<>(SB), NOSPLIT, $0-24 + MOVQ s+0(FP), DI + MOVQ w+8(FP), SI MOVL SI, AX MOVL SI, CX MOVL SI, DX @@ -329,14 +330,14 @@ TEXT sub_ab(SB), NOSPLIT, $0-24 MOVBLZX (DI)(DX*1), DX SALL $16, DX ORL DX, AX - MOVQ AX, ·retval+16(FP) + MOVQ AX, retval+16(FP) RET TEXT ·sub_f(SB), NOSPLIT, $24-68 - MOVQ ·k+0(FP), DI - MOVQ ·r+8(FP), SI - MOVQ ·s+16(FP), DX - MOVQ $·w+24(FP), CX + MOVQ k+0(FP), DI + MOVQ r+8(FP), SI + MOVQ s+16(FP), DX + MOVQ $w+24(FP), CX MOVQ CX, R10 MOVQ SI, R9 MOVQ DX, R8 @@ -367,7 +368,7 @@ inner: ROLL $8, AX MOVQ R8, 0(SP) MOVL AX, 8(SP) - CALL sub_ab(SB) + CALL sub_ab<>(SB) MOVQ 16(SP), AX LEAL -1(BX), DX SARL $2, DX @@ -378,10 +379,10 @@ end: RET TEXT ·sub_aa(SB), NOSPLIT, $0-56 - MOVQ ·i+0(FP), DI - MOVQ ·t+8(FP), SI - MOVQ ·b+16(FP), DX - MOVQ ·m+24(FP), CX + MOVQ i+0(FP), DI + MOVQ t+8(FP), SI + MOVQ b+16(FP), DX + MOVQ m+24(FP), CX MOVL DI, AX MOVLQSX DI, DI MOVQ SI, R8 @@ -407,13 +408,13 @@ TEXT ·sub_aa(SB), NOSPLIT, $0-56 MOVBLZX (AX)(DI*1), AX SALL $4, AX ORB 256(SI)(DX*1), AX - MOVQ AX, ·retval+48(FP) + MOVQ AX, retval+48(FP) RET // func transformInner(x *[0x15]byte, tab *[32][16]byte) TEXT ·transformInner(SB), NOSPLIT, $0-16 - MOVQ ·x+0(FP), DI - MOVQ ·tab+8(FP), SI + MOVQ x+0(FP), DI + MOVQ tab+8(FP), SI MOVQ DI, AX MOVL $1, CX MOVQ SI, DI @@ -446,10 +447,10 @@ lop: RET TEXT ·initState(SB), NOSPLIT, $0-64 - MOVQ ·c+0(FP), DI - MOVQ ·key+8(FP), SI - MOVQ ·data+32(FP), R8 - MOVQ ·counter+56(FP), AX + MOVQ c+0(FP), DI + MOVQ key+8(FP), SI + MOVQ data+32(FP), R8 + MOVQ counter+56(FP), AX MOVOA LC0<>(SB), X0 MOVUPS X0, (DI) MOVOU (SI), X1 @@ -467,8 +468,8 @@ TEXT ·initState(SB), NOSPLIT, $0-64 MOVUPS X6,112(DI) RET -TEXT ·sub_ad(SB), NOSPLIT, $8-24 - MOVQ ·a+0(FP), DI +TEXT sub_ad<>(SB), NOSPLIT, $8-8 + MOVQ a+0(FP), DI MOVQ DI, AX MOVL 40(DI), R10 MOVL 12(DI), R12 @@ -610,11 +611,42 @@ TEXT ·sub_ad(SB), NOSPLIT, $8-24 MOVUPS X0, 32(AX) RET +TEXT ·refreshState(SB), NOSPLIT, $16-8 + MOVQ i+0(FP), BX + MOVB 128(BX), CX + JE ad + SHRQ $1, CX +fr: + MOVQ BX, 0(SP) + MOVQ CX, c-8(SP) + CALL sub_ad<>(SB) + MOVQ c-8(SP), CX + MOVQ i+0(FP), BX + LOOP fr +ad: + MOVOU (BX), X0 + MOVOU 64(BX), X1 + MOVOU 80(BX), X2 + MOVOU 96(BX), X3 + PADDD X1, X0 + MOVOU 48(BX), X4 + MOVUPS X0, (BX) + MOVOU 16(BX), X0 + PADDD X2, X0 + MOVUPS X0, 16(BX) + MOVOU 32(BX), X0 + PADDD X3, X0 + MOVUPS X0, 32(BX) + MOVOU 112(BX), X0 + PADDD X4, X0 + MOVUPS X0, 48(BX) + RET + // func tencentCrc32(tab *crc32.Table, b []byte) uint32 TEXT ·tencentCrc32(SB), NOSPLIT, $0-40 - MOVQ ·tab+0(FP), DI - MOVQ ·bptr+8(FP), SI - MOVQ ·bngas+16(FP), DX + MOVQ tab+0(FP), DI + MOVQ bptr+8(FP), SI + MOVQ bngas+16(FP), DX TESTQ DX, DX JE quickend ADDQ SI, DX @@ -629,7 +661,7 @@ lop: CMPQ SI, DX JNE lop NOTL AX - MOVQ AX, ·bngas+32(FP) + MOVQ AX, bngas+32(FP) RET quickend: XORL AX, AX diff --git a/internal/encryption/t544/encryption_generic.go b/internal/encryption/t544/encryption_generic.go index e74c351..cd3b4f0 100644 --- a/internal/encryption/t544/encryption_generic.go +++ b/internal/encryption/t544/encryption_generic.go @@ -91,12 +91,7 @@ func (c *state) encrypt(data []byte) { dataLen := uint32(len(data)) for dataLen > 0 { if c.p == 0 { - for i := uint8(0); i < c.nr; i += 2 { - sub_ad(c.state[:]) - } - for i := 0; i < 16; i++ { - c.state[i] += c.orgstate[i] - } + refreshState(c) } var sb [16 * 4]byte for i, v := range c.state { diff --git a/internal/encryption/t544/t544.go b/internal/encryption/t544/t544.go index 321fcb1..34ab5b7 100644 --- a/internal/encryption/t544/t544.go +++ b/internal/encryption/t544/t544.go @@ -7,7 +7,6 @@ import ( "crypto/rc4" "encoding/binary" "math/rand" - "unsafe" "github.com/Mrs4s/go-cqhttp/internal/encryption" ) @@ -31,8 +30,10 @@ func init() { // sign t544 algorithm // special thanks to the anonymous contributor who provided the algorithm func sign(curr int64, input []byte) []byte { + var crcData [0x15]byte curr %= 1000000 - input = append(input, []byte{byte(curr >> 24), byte(curr >> 16), byte(curr >> 8), byte(curr)}...) + binary.BigEndian.PutUint32(crcData[:4], uint32(curr)) + input = append(input, crcData[:4]...) var kt [4 + 32 + 4]byte r := rand.New(rand.NewSource(curr)) for i := 0; i < 2; i++ { @@ -51,8 +52,7 @@ func sign(curr int64, input []byte) []byte { k3calc[6], k3calc[7] = 0, 0 rc4Cipher, _ := rc4.NewCipher(key3) rc4Cipher.XORKeyStream(key3, key3) - var crcData [0x15]byte - copy(crcData[4:4+8], (*[8]byte)(unsafe.Pointer(&magic))[:]) + binary.LittleEndian.PutUint64(crcData[4:4+8], magic) tencentEncryptionA(input, kt[4:4+32], crcData[4:4+8]) result := md5.Sum(input) crcData[2] = 1 @@ -61,7 +61,7 @@ func sign(curr int64, input []byte) []byte { binary.BigEndian.PutUint32(crcData[9:13], uint32(curr)) copy(crcData[13:], result[:8]) calcCrc := tencentCrc32(&crc32Table, crcData[2:]) - copy(kt[4+32:4+32+4], (*[4]byte)(unsafe.Pointer(&calcCrc))[:]) + binary.LittleEndian.PutUint32(kt[4+32:4+32+4], calcCrc) crcData[0] = kt[4+32] crcData[1] = kt[4+32+3] nonce := uint32(r.Int() ^ r.Int() ^ r.Int()) diff --git a/internal/encryption/t544/t544_test.go b/internal/encryption/t544/t544_test.go new file mode 100755 index 0000000..1f0f184 --- /dev/null +++ b/internal/encryption/t544/t544_test.go @@ -0,0 +1,22 @@ +package t544 + +import ( + "crypto/rand" + "encoding/hex" + "testing" +) + +func TestT544(t *testing.T) { + r := hex.EncodeToString(sign(0, []byte{})) + if r != "0c05d28b405bce1595c70ffa694ff163d4b600f229482e07de32c8000000003525382c00000000" { + t.Fatal(r) + } +} + +func TestCrash(t *testing.T) { + brand := make([]byte, 4096) + for i := 1; i <= 1024; i++ { + rand.Reader.Read(brand) + sign(123, brand) + } +} From 1ed675d5bf0cf7f56b22fcc79fba76011dda0b42 Mon Sep 17 00:00:00 2001 From: wdvxdr Date: Sun, 9 Apr 2023 17:37:12 +0800 Subject: [PATCH 09/10] internal/t544: add `//go:noescape` --- internal/encryption/t544/encryption.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/internal/encryption/t544/encryption.go b/internal/encryption/t544/encryption.go index 89b09c0..1c2f3e4 100644 --- a/internal/encryption/t544/encryption.go +++ b/internal/encryption/t544/encryption.go @@ -23,25 +23,35 @@ var crc32Table = func() (tab crc32.Table) { return }() +//go:noescape func tencentCrc32(tab *crc32.Table, b []byte) uint32 +//go:noescape func sub_a([]byte, []uint32) +//go:noescape func sub_b([]byte, []uint32) +//go:noescape func sub_c(*[16][16]byte, []byte) +//go:noescape func sub_d(*[16]byte, []byte) +//go:noescape func sub_e(*[256][6]byte, []byte) +//go:noescape func sub_f(*[16]byte, *[15]uint32, *[16][16]byte) (w [44]uint32) func sub_aa(int, *[16][2][16][16]byte, *[16]byte, []byte) byte // transformInner see com/tencent/mobileqq/dt/model/FEBound +// +//go:noescape func transformInner(*[0x15]byte, *[32][16]byte) +//go:noescape func initState(*state, []byte, []byte, uint64) func (c *state) init(key []byte, data []byte, counter uint64, nr uint8) { @@ -50,4 +60,5 @@ func (c *state) init(key []byte, data []byte, counter uint64, nr uint8) { initState(c, key, data, counter) } +//go:noescape func refreshState(c *state) From 42606a825d0499ec7e2291cabbf34804545fc0aa Mon Sep 17 00:00:00 2001 From: wdvxdr Date: Sun, 9 Apr 2023 17:51:32 +0800 Subject: [PATCH 10/10] internal/download: disable http when not visiting go-cqhttp.org --- cmd/gocq/main.go | 2 +- internal/download/download.go | 35 +++++++++++++++++++++----- internal/encryption/t544/encryption.go | 1 + pkg/onebot/value.go | 1 + 4 files changed, 32 insertions(+), 7 deletions(-) diff --git a/cmd/gocq/main.go b/cmd/gocq/main.go index 2e6c85a..852eb01 100644 --- a/cmd/gocq/main.go +++ b/cmd/gocq/main.go @@ -364,7 +364,7 @@ func LoginInteract() { }) saveToken() cli.AllowSlider = true - download.SetGlobalTimeout(time.Duration(base.HTTPTimeout) * time.Second) // 在登录完成后设置, 防止在堵塞协议更新 + download.SetTimeout(time.Duration(base.HTTPTimeout) * time.Second) // 在登录完成后设置, 防止在堵塞协议更新 log.Infof("登录成功 欢迎使用: %v", cli.Nickname) log.Info("开始加载好友列表...") global.Check(cli.ReloadFriendList(), true) diff --git a/internal/download/download.go b/internal/download/download.go index 7622e4c..a82af5a 100644 --- a/internal/download/download.go +++ b/internal/download/download.go @@ -4,6 +4,7 @@ package download import ( "bufio" "compress/gzip" + "crypto/tls" "fmt" "io" "net/http" @@ -22,15 +23,28 @@ import ( var client = &http.Client{ Transport: &http.Transport{ - Proxy: func(request *http.Request) (u *url.URL, e error) { + Proxy: func(request *http.Request) (*url.URL, error) { if base.Proxy == "" { return http.ProxyFromEnvironment(request) } return url.Parse(base.Proxy) }, - ForceAttemptHTTP2: false, - MaxConnsPerHost: 0, - MaxIdleConns: 0, + // Disable http2 + TLSNextProto: map[string]func(authority string, c *tls.Conn) http.RoundTripper{}, + MaxIdleConnsPerHost: 999, + }, + Timeout: time.Second * 5, +} + +var clienth2 = &http.Client{ + Transport: &http.Transport{ + Proxy: func(request *http.Request) (*url.URL, error) { + if base.Proxy == "" { + return http.ProxyFromEnvironment(request) + } + return url.Parse(base.Proxy) + }, + ForceAttemptHTTP2: true, MaxIdleConnsPerHost: 999, }, Timeout: time.Second * 5, @@ -42,11 +56,13 @@ var ErrOverSize = errors.New("oversize") // UserAgent HTTP请求时使用的UA const UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 Edg/87.0.664.66" -func SetGlobalTimeout(t time.Duration) { +// SetTimeout set internal/download client timeout +func SetTimeout(t time.Duration) { if t == 0 { t = time.Second * 10 } client.Timeout = t + clienth2.Timeout = t } // Request is a file download request @@ -58,6 +74,13 @@ type Request struct { Body io.Reader } +func (r Request) client() *http.Client { + if strings.Contains(r.URL, "go-cqhttp.org") { + return clienth2 + } + return client +} + func (r Request) do() (*http.Response, error) { if r.Method == "" { r.Method = http.MethodGet @@ -72,7 +95,7 @@ func (r Request) do() (*http.Response, error) { req.Header.Set(k, v) } - return client.Do(req) + return r.client().Do(req) } func (r Request) body() (io.ReadCloser, error) { diff --git a/internal/encryption/t544/encryption.go b/internal/encryption/t544/encryption.go index 1c2f3e4..a2c6bad 100644 --- a/internal/encryption/t544/encryption.go +++ b/internal/encryption/t544/encryption.go @@ -44,6 +44,7 @@ func sub_e(*[256][6]byte, []byte) //go:noescape func sub_f(*[16]byte, *[15]uint32, *[16][16]byte) (w [44]uint32) +//go:noescape func sub_aa(int, *[16][2][16][16]byte, *[16]byte, []byte) byte // transformInner see com/tencent/mobileqq/dt/model/FEBound diff --git a/pkg/onebot/value.go b/pkg/onebot/value.go index 6192ef8..eefa73d 100644 --- a/pkg/onebot/value.go +++ b/pkg/onebot/value.go @@ -31,6 +31,7 @@ type ( // Kind is the kind of Value. type Kind int +// Kind const ( KindAny Kind = iota KindBool