1
0
mirror of https://github.com/Mrs4s/go-cqhttp.git synced 2025-05-04 11:07:39 +08:00

Merge branch 'dev'

This commit is contained in:
Mrs4s 2023-04-13 00:19:43 +08:00
commit 2af55d6a67
No known key found for this signature in database
GPG Key ID: 3186E98FA19CE3A7
18 changed files with 682 additions and 150 deletions

View File

@ -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)
@ -218,8 +217,14 @@ func loginResponseProcessor(res *client.LoginResponse) error {
case client.OtherLoginError, client.UnknownLoginError, client.TooManySMSRequestError:
msg := res.ErrorMessage
log.Warnf("登录失败: %v Code: %v", msg, res.Code)
if res.Code == 235 {
log.Warnf("请删除 device.json 后重试.")
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 升级到最新协议后重试")
}
log.Infof("按 Enter 继续....")
readLine()

View File

@ -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))
}
@ -368,6 +364,7 @@ func LoginInteract() {
})
saveToken()
cli.AllowSlider = true
download.SetTimeout(time.Duration(base.HTTPTimeout) * time.Second) // 在登录完成后设置, 防止在堵塞协议更新
log.Infof("登录成功 欢迎使用: %v", cli.Nickname)
log.Info("开始加载好友列表...")
global.Check(cli.ReloadFriendList(), true)
@ -379,7 +376,6 @@ func LoginInteract() {
base.Account.Status = 0
}
cli.SetOnlineStatus(allowStatus[base.Account.Status])
servers.Run(coolq.NewQQBot(cli))
log.Info("资源初始化完成, 开始处理信息.")
log.Info("アトリは、高性能ですから!")

View File

@ -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)
}

View File

@ -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 {

View File

@ -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

View File

@ -4,6 +4,7 @@ package download
import (
"bufio"
"compress/gzip"
"crypto/tls"
"fmt"
"io"
"net/http"
@ -22,18 +23,31 @@ 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 * 15,
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,
}
// ErrOverSize 响应主体过大时返回此错误
@ -42,6 +56,15 @@ 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"
// 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
type Request struct {
Method string
@ -51,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
@ -65,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) {

View File

@ -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
}()

View File

@ -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

View File

@ -23,25 +23,36 @@ 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)
//go:noescape
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 +61,5 @@ func (c *state) init(key []byte, data []byte, counter uint64, nr uint8) {
initState(c, key, data, counter)
}
func sub_ad([]uint32)
//go:noescape
func refreshState(c *state)

View File

@ -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

View File

@ -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 {

View File

@ -7,7 +7,6 @@ import (
"crypto/rc4"
"encoding/binary"
"math/rand"
"unsafe"
"github.com/Mrs4s/go-cqhttp/internal/encryption"
)
@ -24,17 +23,17 @@ 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
// 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++ {
@ -53,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
@ -63,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())

View File

@ -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)
}
}

View File

@ -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)

View File

@ -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 {

78
pkg/onebot/attr.go Normal file
View File

@ -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()
}

31
pkg/onebot/kind_string.go Normal file
View File

@ -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]]
}

355
pkg/onebot/value.go Normal file
View File

@ -0,0 +1,355 @@
// 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
// Kind
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()))
}
}