mirror of
https://github.com/Mrs4s/go-cqhttp.git
synced 2025-06-29 19:43:24 +00:00
Compare commits
20 Commits
Author | SHA1 | Date | |
---|---|---|---|
9c1390c75c | |||
b958046a27 | |||
19906eba36 | |||
8e6e79f734 | |||
9b9ecd6a41 | |||
c8e480d12f | |||
5bf64ee743 | |||
bad3c86912 | |||
2af55d6a67 | |||
42606a825d | |||
1ed675d5bf | |||
91b4394d9b | |||
0b90074a48 | |||
55cb80dccc | |||
54995fc101 | |||
8acc9f39c2 | |||
13325634c0 | |||
7b2d1fd573 | |||
637d46f282 | |||
1e42b2c450 |
@ -42,3 +42,4 @@ WORKDIR /data
|
||||
VOLUME [ "/data" ]
|
||||
|
||||
ENTRYPOINT [ "/docker-entrypoint.sh" ]
|
||||
CMD [ "/app/cqhttp" ]
|
||||
|
@ -14,27 +14,19 @@ 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/Mrs4s/go-cqhttp/internal/base"
|
||||
"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/download"
|
||||
)
|
||||
|
||||
var console = bufio.NewReader(os.Stdin)
|
||||
|
||||
func init() {
|
||||
wrapper.DandelionEnergy = energy
|
||||
}
|
||||
|
||||
func readLine() (str string) {
|
||||
str, _ = console.ReadString('\n')
|
||||
str = strings.TrimSpace(str)
|
||||
@ -218,8 +210,13 @@ 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:
|
||||
log.Warnf("你的账号被限制登录, 请配置 SignServer 后重试")
|
||||
}
|
||||
log.Infof("按 Enter 继续....")
|
||||
readLine()
|
||||
@ -269,32 +266,47 @@ func fetchCaptcha(id string) string {
|
||||
}
|
||||
|
||||
func energy(uin uint64, id string, appVersion string, salt []byte) ([]byte, error) {
|
||||
if localSigner, ok := encryption.T544Signer[appVersion]; ok {
|
||||
log.Debugf("use local T544Signer v%s", appVersion)
|
||||
result := localSigner(time.Now().UnixMicro(), salt)
|
||||
log.Debugf("t544 sign result: %x", result)
|
||||
return result, nil
|
||||
signServer := base.SignServer
|
||||
if !strings.HasSuffix(signServer, "/") {
|
||||
signServer += "/"
|
||||
}
|
||||
log.Debugf("fallback to remote T544Signer v%s", appVersion)
|
||||
signServer := "https://captcha.go-cqhttp.org/sdk/dandelion/energy"
|
||||
if base.SignServerOverwrite != "" {
|
||||
signServer = base.SignServerOverwrite
|
||||
response, err := download.Request{
|
||||
Method: http.MethodGet,
|
||||
URL: signServer + "custom_energy" + fmt.Sprintf("?data=%v&salt=%v", id, hex.EncodeToString(salt)),
|
||||
}.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
|
||||
}
|
||||
|
||||
func sign(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 += "/"
|
||||
}
|
||||
response, err := download.Request{
|
||||
Method: http.MethodPost,
|
||||
URL: signServer,
|
||||
URL: signServer + "sign",
|
||||
Header: map[string]string{"Content-Type": "application/x-www-form-urlencoded"},
|
||||
Body: bytes.NewReader([]byte(fmt.Sprintf("uin=%v&id=%s&salt=%s&version=%s", uin, id, hex.EncodeToString(salt), appVersion))),
|
||||
Body: bytes.NewReader([]byte(fmt.Sprintf("uin=%v&qua=%s&cmd=%s&seq=%v&buffer=%v", uin, qua, cmd, seq, hex.EncodeToString(buff)))),
|
||||
}.Bytes()
|
||||
if err != nil {
|
||||
log.Errorf("获取T544时出现问题: %v", err)
|
||||
return nil, err
|
||||
log.Warnf("获取sso sign时出现错误: %v server: %v", err, signServer)
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
sign, err := hex.DecodeString(gjson.GetBytes(response, "result").String())
|
||||
if err != nil || len(sign) == 0 {
|
||||
log.Errorf("获取T544时出现问题: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
log.Debugf("t544 sign result: %x", sign)
|
||||
return sign, nil
|
||||
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())
|
||||
return sign, extra, token, nil
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import (
|
||||
|
||||
"github.com/Mrs4s/MiraiGo/binary"
|
||||
"github.com/Mrs4s/MiraiGo/client"
|
||||
"github.com/Mrs4s/MiraiGo/wrapper"
|
||||
para "github.com/fumiama/go-hide-param"
|
||||
rotatelogs "github.com/lestrrat-go/file-rotatelogs"
|
||||
"github.com/pkg/errors"
|
||||
@ -22,14 +23,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"
|
||||
@ -164,55 +164,60 @@ func LoginInteract() {
|
||||
}
|
||||
}
|
||||
|
||||
if base.SignServer != "-" && base.SignServer != "" {
|
||||
log.Infof("使用服务器 %s 进行数据包签名", base.SignServer)
|
||||
wrapper.DandelionEnergy = energy
|
||||
wrapper.FekitGetSign = sign
|
||||
} else {
|
||||
log.Warnf("警告: 未配置签名服务器, 这可能会导致登录 45 错误码或发送消息被风控")
|
||||
}
|
||||
|
||||
if base.Account.Encrypt {
|
||||
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 +373,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 +385,6 @@ func LoginInteract() {
|
||||
base.Account.Status = 0
|
||||
}
|
||||
cli.SetOnlineStatus(allowStatus[base.Account.Status])
|
||||
|
||||
servers.Run(coolq.NewQQBot(cli))
|
||||
log.Info("资源初始化完成, 开始处理信息.")
|
||||
log.Info("アトリは、高性能ですから!")
|
||||
|
@ -617,6 +617,7 @@ func (bot *CQBot) CQUploadPrivateFile(userID int64, file, name string) global.MS
|
||||
log.Warnf("上传私聊文件 %v 失败: %+v", file, err)
|
||||
return Failed(100, "OPEN_FILE_ERROR", "打开文件失败")
|
||||
}
|
||||
defer func() { _ = fileBody.Close() }()
|
||||
localFile := &client.LocalFile{
|
||||
FileName: name,
|
||||
Body: fileBody,
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -92,7 +92,7 @@ func (bot *CQBot) formatGroupMessage(m *message.GroupMessage) *event {
|
||||
"name": m.Sender.AnonymousInfo.AnonymousNick,
|
||||
}
|
||||
gm["sender"].(global.MSG)["nickname"] = "匿名消息"
|
||||
gm["sub_type"] = "anonymous"
|
||||
typ = "message/group/anonymous"
|
||||
} else {
|
||||
group := bot.Client.FindGroup(m.GroupCode)
|
||||
mem := group.FindMember(m.Sender.Uin)
|
||||
|
@ -713,7 +713,7 @@ func (bot *CQBot) ConvertElement(spec *onebot.Spec, elem msg.Element, sourceType
|
||||
MusicType: message.CloudMusic,
|
||||
Title: info.Get("name").String(),
|
||||
Summary: artistName,
|
||||
Url: "https://y.music.163.com/m/song/" + id,
|
||||
Url: "https://music.163.com/song/?id=" + id,
|
||||
PictureUrl: info.Get("album.picUrl").String(),
|
||||
MusicUrl: "https://music.163.com/song/media/outer/url?id=" + id,
|
||||
}, nil
|
||||
|
@ -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 {
|
||||
|
@ -17,4 +17,4 @@ chown -R ${UID}:${GID} /app /data
|
||||
chmod +x /app/cqhttp
|
||||
|
||||
echo "Starting..."
|
||||
su-exec ${USER} /app/cqhttp
|
||||
su-exec ${USER} "$@"
|
||||
|
2
go.mod
2
go.mod
@ -5,7 +5,7 @@ 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-20230401072048-f8d9841755b5
|
||||
github.com/Mrs4s/MiraiGo v0.0.0-20230627090859-19e3d172596e
|
||||
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
|
||||
|
4
go.sum
4
go.sum
@ -4,8 +4,8 @@ github.com/FloatTech/ttl v0.0.0-20220715042055-15612be72f5b h1:tvciXWq2nuvTbFeJG
|
||||
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-20230401072048-f8d9841755b5 h1:E4fIQ0l/LNZK44NjdViRb/hx4cIeHXyQFPzzkx7cjVE=
|
||||
github.com/Mrs4s/MiraiGo v0.0.0-20230401072048-f8d9841755b5/go.mod h1:mU3fBFU+7eO0kaGes7YRKtzIDtwIU84nSSwTV7NK2b0=
|
||||
github.com/Mrs4s/MiraiGo v0.0.0-20230627090859-19e3d172596e h1:99itMjI//+KaFF0+0QCBg/uHhGMJ99jG2lP6z/UnOsU=
|
||||
github.com/Mrs4s/MiraiGo v0.0.0-20230627090859-19e3d172596e/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=
|
||||
|
@ -38,7 +38,8 @@ var (
|
||||
FastStart bool // 是否为快速启动
|
||||
AllowTempSession bool // 是否允许发送临时会话信息
|
||||
UpdateProtocol bool // 是否更新协议
|
||||
SignServerOverwrite string // 使用特定的服务器进行签名
|
||||
SignServer string // 使用特定的服务器进行签名
|
||||
HTTPTimeout int
|
||||
|
||||
PostFormat string // 上报格式 string or array
|
||||
Proxy string // 存储 proxy_rewrite,用于设置代理
|
||||
@ -63,7 +64,6 @@ func Parse() {
|
||||
d := flag.Bool("D", false, "debug mode")
|
||||
flag.BoolVar(&FastStart, "faststart", false, "skip waiting 5 seconds")
|
||||
flag.BoolVar(&UpdateProtocol, "update-protocol", false, "update protocol")
|
||||
flag.StringVar(&SignServerOverwrite, "sign-server", "", "use special server to sign tlv")
|
||||
flag.Parse()
|
||||
|
||||
if *d {
|
||||
@ -88,6 +88,8 @@ func Init() {
|
||||
ReportSelfMessage = conf.Message.ReportSelfMessage
|
||||
UseSSOAddress = conf.Account.UseSSOAddress
|
||||
AllowTempSession = conf.Account.AllowTempSession
|
||||
SignServer = conf.Account.SignServer
|
||||
HTTPTimeout = conf.Message.HTTPTimeout
|
||||
}
|
||||
{ // others
|
||||
Proxy = conf.Message.ProxyRewrite
|
||||
|
@ -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) {
|
||||
|
@ -1,3 +0,0 @@
|
||||
package encryption
|
||||
|
||||
var T544Signer = map[string]func(int64, []byte) []byte{}
|
@ -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
|
||||
}()
|
@ -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
|
File diff suppressed because one or more lines are too long
@ -1,53 +0,0 @@
|
||||
//go:build amd64
|
||||
|
||||
package t544
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"hash/crc32"
|
||||
"io"
|
||||
)
|
||||
|
||||
var crc32Table = func() (tab crc32.Table) {
|
||||
f, err := cryptoZip.Open("crc32.bin")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
data, err := io.ReadAll(f)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for i := range tab {
|
||||
tab[i] = binary.LittleEndian.Uint32(data[i*4 : (i+1)*4])
|
||||
}
|
||||
return
|
||||
}()
|
||||
|
||||
func tencentCrc32(tab *crc32.Table, b []byte) uint32
|
||||
|
||||
func sub_a([]byte, []uint32)
|
||||
|
||||
func sub_b([]byte, []uint32)
|
||||
|
||||
func sub_c(*[16][16]byte, []byte)
|
||||
|
||||
func sub_d(*[16]byte, []byte)
|
||||
|
||||
func sub_e(*[256][6]byte, []byte)
|
||||
|
||||
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
|
||||
func transformInner(*[0x15]byte, *[32][16]byte)
|
||||
|
||||
func initState(*state, []byte, []byte, uint64)
|
||||
|
||||
func (c *state) init(key []byte, data []byte, counter uint64, nr uint8) {
|
||||
c.nr = nr
|
||||
c.p = 0
|
||||
initState(c, key, data, counter)
|
||||
}
|
||||
|
||||
func sub_ad([]uint32)
|
@ -1,637 +0,0 @@
|
||||
//go:build amd64
|
||||
// +build amd64
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
DATA LC0<>+0(SB)/4, $1634760805
|
||||
DATA LC0<>+4(SB)/4, $857760878
|
||||
DATA LC0<>+8(SB)/4, $2036477234
|
||||
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 CX, DX
|
||||
MOVBLZX 3(CX), CX
|
||||
XORB CX, (DI)
|
||||
MOVBLZX 2(DX), CX
|
||||
XORB CX, 1(DI)
|
||||
MOVBLZX 1(DX), CX
|
||||
XORB CX, 2(DI)
|
||||
MOVBLZX (DX), CX
|
||||
XORB CX, 3(DI)
|
||||
MOVBLZX 7(DX), CX
|
||||
XORB CX, 4(DI)
|
||||
MOVBLZX 6(DX), CX
|
||||
XORB CX, 5(DI)
|
||||
MOVBLZX 5(DX), CX
|
||||
XORB CX, 6(DI)
|
||||
MOVBLZX 4(DX), CX
|
||||
XORB CX, 7(DI)
|
||||
MOVBLZX 11(DX),CX
|
||||
XORB CX, 8(DI)
|
||||
MOVBLZX 10(DX),CX
|
||||
XORB CX, 9(DI)
|
||||
MOVBLZX 9(DX), CX
|
||||
XORB CX,10(DI)
|
||||
MOVBLZX 8(DX), CX
|
||||
XORB CX,11(DI)
|
||||
MOVBLZX 15(DX),CX
|
||||
XORB CX,12(DI)
|
||||
MOVBLZX 14(DX),CX
|
||||
XORB CX,13(DI)
|
||||
MOVBLZX 13(DX),CX
|
||||
XORB CX,14(DI)
|
||||
MOVBLZX 12(DX),DX
|
||||
XORB DL,15(DI)
|
||||
RET
|
||||
|
||||
TEXT ·sub_b(SB), NOSPLIT, $0-48
|
||||
MOVQ ·a+0(FP), DI
|
||||
MOVQ ·b+24(FP), CX
|
||||
MOVQ CX, DX
|
||||
MOVBLZX 3(CX), CX
|
||||
XORB CX, (DI)
|
||||
MOVBLZX 6(DX), CX
|
||||
XORB CX, 1(DI)
|
||||
MOVBLZX 9(DX), CX
|
||||
XORB CX, 2(DI)
|
||||
MOVBLZX 12(DX),CX
|
||||
XORB CX, 3(DI)
|
||||
MOVBLZX 7(DX), CX
|
||||
XORB CX, 4(DI)
|
||||
MOVBLZX 10(DX),CX
|
||||
XORB CX, 5(DI)
|
||||
MOVBLZX 13(DX),CX
|
||||
XORB CX, 6(DI)
|
||||
MOVBLZX (DX), CX
|
||||
XORB CX,7(DI)
|
||||
MOVBLZX 11(DX),CX
|
||||
XORB CX,8(DI)
|
||||
MOVBLZX 14(DX),CX
|
||||
XORB CX,9(DI)
|
||||
MOVBLZX 1(DX), CX
|
||||
XORB CX,10(DI)
|
||||
MOVBLZX 4(DX), CX
|
||||
XORB CX,11(DI)
|
||||
MOVBLZX 15(DX),CX
|
||||
XORB CX,12(DI)
|
||||
MOVBLZX 2(DX), CX
|
||||
XORB CX,13(DI)
|
||||
MOVBLZX 5(DX), CX
|
||||
XORB CX,14(DI)
|
||||
MOVBLZX 8(DX), DX
|
||||
XORB DL,15(DI)
|
||||
RET
|
||||
|
||||
|
||||
TEXT ·sub_c(SB), NOSPLIT, $0-32
|
||||
MOVQ ·a+0(FP), DI
|
||||
MOVQ ·b+8(FP), SI
|
||||
MOVQ SI, AX
|
||||
MOVBLZX (SI), SI
|
||||
MOVL SI, CX
|
||||
ANDL $15, SI
|
||||
SHRL $4, CX
|
||||
SHLL $4, CX
|
||||
ADDL SI, CX
|
||||
MOVBLZX 1(AX), SI
|
||||
MOVLQSX CX, CX
|
||||
MOVBLZX (DI)(CX*1), CX
|
||||
MOVB CX, (AX)
|
||||
MOVL SI, CX
|
||||
ANDL $15, SI
|
||||
SHRL $4, CX
|
||||
SHLL $4, CX
|
||||
ADDL SI, CX
|
||||
MOVBLZX 2(AX), SI
|
||||
MOVLQSX CX, CX
|
||||
MOVBLZX (DI)(CX*1), CX
|
||||
MOVB CX, 1(AX)
|
||||
MOVL SI, CX
|
||||
ANDL $15, SI
|
||||
SHRL $4, CX
|
||||
SHLL $4, CX
|
||||
ADDL SI, CX
|
||||
MOVBLZX 3(AX), SI
|
||||
MOVLQSX CX, CX
|
||||
MOVBLZX (DI)(CX*1), CX
|
||||
MOVB CX, 2(AX)
|
||||
MOVL SI, CX
|
||||
ANDL $15, SI
|
||||
SHRL $4, CX
|
||||
SHLL $4, CX
|
||||
ADDL SI, CX
|
||||
MOVBLZX 4(AX), SI
|
||||
MOVLQSX CX, CX
|
||||
MOVBLZX (DI)(CX*1), CX
|
||||
MOVB CX, 3(AX)
|
||||
MOVL SI, CX
|
||||
ANDL $15, SI
|
||||
SHRL $4, CX
|
||||
SHLL $4, CX
|
||||
ADDL SI, CX
|
||||
MOVBLZX 5(AX), SI
|
||||
MOVLQSX CX, CX
|
||||
MOVBLZX (DI)(CX*1), CX
|
||||
MOVB CX, 4(AX)
|
||||
MOVL SI, CX
|
||||
ANDL $15, SI
|
||||
SHRL $4, CX
|
||||
SHLL $4, CX
|
||||
ADDL SI, CX
|
||||
MOVBLZX 6(AX), SI
|
||||
MOVLQSX CX, CX
|
||||
MOVBLZX (DI)(CX*1), CX
|
||||
MOVB CX, 5(AX)
|
||||
MOVL SI, CX
|
||||
ANDL $15, SI
|
||||
SHRL $4, CX
|
||||
SHLL $4, CX
|
||||
ADDL SI, CX
|
||||
MOVBLZX 7(AX), SI
|
||||
MOVLQSX CX, CX
|
||||
MOVBLZX (DI)(CX*1), CX
|
||||
MOVB CX, 6(AX)
|
||||
MOVL SI, CX
|
||||
ANDL $15, SI
|
||||
SHRL $4, CX
|
||||
SHLL $4, CX
|
||||
ADDL SI, CX
|
||||
MOVBLZX 8(AX), SI
|
||||
MOVLQSX CX, CX
|
||||
MOVBLZX (DI)(CX*1), CX
|
||||
MOVB CX, 7(AX)
|
||||
MOVL SI, CX
|
||||
ANDL $15, SI
|
||||
SHRL $4, CX
|
||||
SHLL $4, CX
|
||||
ADDL SI, CX
|
||||
MOVBLZX 9(AX), SI
|
||||
MOVLQSX CX, CX
|
||||
MOVBLZX (DI)(CX*1), CX
|
||||
MOVB CX, 8(AX)
|
||||
MOVL SI, CX
|
||||
ANDL $15, SI
|
||||
SHRL $4, CX
|
||||
SHLL $4, CX
|
||||
ADDL SI, CX
|
||||
MOVBLZX 10(AX), SI
|
||||
MOVLQSX CX, CX
|
||||
MOVBLZX (DI)(CX*1), CX
|
||||
MOVB CX, 9(AX)
|
||||
MOVL SI, CX
|
||||
ANDL $15, SI
|
||||
SHRL $4, CX
|
||||
SHLL $4, CX
|
||||
ADDL SI, CX
|
||||
MOVBLZX 11(AX), SI
|
||||
MOVLQSX CX, CX
|
||||
MOVBLZX (DI)(CX*1), CX
|
||||
MOVB CX, 10(AX)
|
||||
MOVL SI, CX
|
||||
ANDL $15, SI
|
||||
SHRL $4, CX
|
||||
SHLL $4, CX
|
||||
ADDL SI, CX
|
||||
MOVBLZX 12(AX), SI
|
||||
MOVLQSX CX, CX
|
||||
MOVBLZX (DI)(CX*1), CX
|
||||
MOVB CX, 11(AX)
|
||||
MOVL SI, CX
|
||||
ANDL $15, SI
|
||||
SHRL $4, CX
|
||||
SHLL $4, CX
|
||||
ADDL SI, CX
|
||||
MOVBLZX 13(AX), SI
|
||||
MOVLQSX CX, CX
|
||||
MOVBLZX (DI)(CX*1), CX
|
||||
MOVB CX, 12(AX)
|
||||
MOVL SI, CX
|
||||
ANDL $15, SI
|
||||
SHRL $4, CX
|
||||
SHLL $4, CX
|
||||
ADDL SI, CX
|
||||
MOVBLZX 14(AX), SI
|
||||
MOVLQSX CX, CX
|
||||
MOVBLZX (DI)(CX*1), CX
|
||||
MOVB CX, 13(AX)
|
||||
MOVL SI, CX
|
||||
ANDL $15, SI
|
||||
SHRL $4, CX
|
||||
SHLL $4, CX
|
||||
ADDL SI, CX
|
||||
MOVBLZX 15(AX), SI
|
||||
MOVLQSX CX, CX
|
||||
MOVBLZX (DI)(CX*1), CX
|
||||
MOVB CX, 14(AX)
|
||||
MOVL SI, CX
|
||||
ANDL $15, SI
|
||||
SHRL $4, CX
|
||||
SHLL $4, CX
|
||||
ADDL SI, CX
|
||||
MOVLQSX CX, CX
|
||||
MOVBLZX (DI)(CX*1), CX
|
||||
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
|
||||
MOVOU X0, in-16(SP)
|
||||
MOVQ SI, DI
|
||||
ADDQ $15, DI
|
||||
MOVB $16, CX
|
||||
STD
|
||||
lop:
|
||||
LEAQ -1(CX), AX
|
||||
XLAT
|
||||
MOVBLZX in-16(SP)(AX*1), AX
|
||||
STOSB
|
||||
LOOP lop
|
||||
RET
|
||||
|
||||
TEXT ·sub_e(SB), NOSPLIT, $0-32
|
||||
MOVQ ·a+0(FP), DI
|
||||
MOVQ ·n+8(FP), SI
|
||||
MOVQ $4, AX
|
||||
lop:
|
||||
MOVBQZX -4(SI)(AX*4), DX
|
||||
MOVBQZX -3(SI)(AX*4), CX
|
||||
MOVBQZX -2(SI)(AX*4), R10
|
||||
MOVBQZX -1(SI)(AX*4), R8
|
||||
LEAQ (DX)(DX*2), R9
|
||||
LEAQ (R9*2), R9
|
||||
LEAQ (CX)(CX*2), R11
|
||||
LEAQ (R11*2), R11
|
||||
LEAQ (R10)(R10*2), BX
|
||||
LEAQ (BX*2), BX
|
||||
MOVB DX, R13
|
||||
XORB CX, DX
|
||||
XORB R10, CX
|
||||
MOVB (DI)(R9*1), R12
|
||||
XORB 1(DI)(R11*1), R12
|
||||
XORB R8, R10
|
||||
XORB R12, R10
|
||||
MOVB R10, -4(SI)(AX*4)
|
||||
MOVB (DI)(R11*1), R10
|
||||
XORB 1(DI)(BX*1), R10
|
||||
XORB R8, R13
|
||||
XORB R10, R13
|
||||
MOVB R13, -3(SI)(AX*4)
|
||||
MOVB (DI)(BX*1), R10
|
||||
LEAQ (R8)(R8*2), R8
|
||||
LEAQ (R8*2), R8
|
||||
XORB 1(DI)(R8*1), R10
|
||||
XORB R10, DX
|
||||
MOVB DX, -2(SI)(AX*4)
|
||||
MOVB 1(DI)(R9*1), DX
|
||||
XORB (DI)(R8*1), DX
|
||||
XORB DX, CX
|
||||
MOVB CX, -1(SI)(AX*4)
|
||||
DECB AX
|
||||
JNZ lop
|
||||
RET
|
||||
|
||||
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
|
||||
SHRL $28, AX
|
||||
SHRL $24, CX
|
||||
ANDL $15, CX
|
||||
SALL $4, AX
|
||||
ADDL CX, AX
|
||||
MOVBLZX SI, CX
|
||||
MOVBLZX (DI)(AX*1), AX
|
||||
MOVBLZX (DI)(CX*1), CX
|
||||
SALL $24, AX
|
||||
ORL CX, AX
|
||||
MOVL SI, CX
|
||||
SHRL $8, SI
|
||||
SHRL $8, CX
|
||||
ANDL $15, SI
|
||||
ANDL $240, CX
|
||||
ADDL SI, CX
|
||||
MOVBLZX (DI)(CX*1), CX
|
||||
SALL $8, CX
|
||||
ORL CX, AX
|
||||
MOVL DX, CX
|
||||
SHRL $16, DX
|
||||
SHRL $16, CX
|
||||
ANDL $15, DX
|
||||
ANDL $240, CX
|
||||
ADDL CX, DX
|
||||
MOVBLZX (DI)(DX*1), DX
|
||||
SALL $16, DX
|
||||
ORL DX, AX
|
||||
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 CX, R10
|
||||
MOVQ SI, R9
|
||||
MOVQ DX, R8
|
||||
MOVL $4, BX
|
||||
MOVL (DI), AX
|
||||
BSWAPL AX
|
||||
MOVL AX, (CX)
|
||||
MOVL 4(DI), AX
|
||||
BSWAPL AX
|
||||
MOVL AX, 4(CX)
|
||||
MOVL 8(DI), AX
|
||||
BSWAPL AX
|
||||
MOVL AX, 8(CX)
|
||||
MOVL 12(DI), AX
|
||||
BSWAPL AX
|
||||
MOVL AX, 12(CX)
|
||||
JMP inner
|
||||
for:
|
||||
XORL -16(R10)(BX*4), AX
|
||||
MOVL AX, (R10)(BX*4)
|
||||
ADDQ $1, BX
|
||||
CMPQ BX, $44
|
||||
JE end
|
||||
inner:
|
||||
MOVL -4(R10)(BX*4), AX
|
||||
TESTB $3, BX
|
||||
JNE for
|
||||
ROLL $8, AX
|
||||
MOVQ R8, 0(SP)
|
||||
MOVL AX, 8(SP)
|
||||
CALL sub_ab(SB)
|
||||
MOVQ 16(SP), AX
|
||||
LEAL -1(BX), DX
|
||||
SARL $2, DX
|
||||
MOVLQSX DX, DX
|
||||
XORL (R9)(DX*4), AX
|
||||
JMP for
|
||||
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
|
||||
MOVL DI, AX
|
||||
MOVLQSX DI, DI
|
||||
MOVQ SI, R8
|
||||
MOVQ DX, SI
|
||||
MOVBLZX (CX)(DI*1), CX
|
||||
ANDL $15, AX
|
||||
MOVBLZX (SI)(AX*1), SI
|
||||
MOVQ AX, DX
|
||||
MOVL CX, AX
|
||||
SALQ $9, DX
|
||||
ANDL $15, CX
|
||||
SHRB $4, AX
|
||||
MOVL SI, DI
|
||||
ADDQ R8, DX
|
||||
SALQ $4, CX
|
||||
ANDL $15, AX
|
||||
SHRB $4, DI
|
||||
ANDL $15, SI
|
||||
SALQ $4, AX
|
||||
ANDL $15, DI
|
||||
ADDQ DX, AX
|
||||
ADDQ CX, DX
|
||||
MOVBLZX (AX)(DI*1), AX
|
||||
SALL $4, AX
|
||||
ORB 256(SI)(DX*1), AX
|
||||
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 DI, AX
|
||||
MOVL $1, CX
|
||||
MOVQ SI, DI
|
||||
MOVQ AX, SI
|
||||
lop:
|
||||
MOVBLZX (SI), R8
|
||||
LEAL -1(CX), AX
|
||||
ADDQ $1, SI
|
||||
ANDL $31, AX
|
||||
MOVL R8, DX
|
||||
SALL $4, AX
|
||||
ANDL $15, R8
|
||||
SHRB $4, DX
|
||||
MOVBLZX DX, DX
|
||||
ADDL DX, AX
|
||||
CDQE
|
||||
MOVBLSX (DI)(AX*1), AX
|
||||
SALL $4, AX
|
||||
MOVL AX, DX
|
||||
MOVL CX, AX
|
||||
ADDL $2, CX
|
||||
ANDL $31, AX
|
||||
SALL $4, AX
|
||||
ADDL R8, AX
|
||||
CDQE
|
||||
ORB (DI)(AX*1), DX
|
||||
MOVB DX, -1(SI)
|
||||
CMPL CX, $43
|
||||
JNE 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
|
||||
MOVOA LC0<>(SB), X0
|
||||
MOVUPS X0, (DI)
|
||||
MOVOU (SI), X1
|
||||
MOVOU (DI), X3
|
||||
MOVUPS X1, 16(DI)
|
||||
MOVOU 16(SI), X2
|
||||
MOVQ AX, 48(DI)
|
||||
MOVUPS X2, 32(DI)
|
||||
MOVQ (R8), AX
|
||||
MOVUPS X3, 64(DI)
|
||||
MOVQ AX, 56(DI)
|
||||
MOVQ 48(DI), AX
|
||||
MOVUPS X1, 80(DI)
|
||||
MOVUPS X2, 96(DI)
|
||||
MOVUPS X6,112(DI)
|
||||
RET
|
||||
|
||||
TEXT ·sub_ad(SB), NOSPLIT, $8-24
|
||||
MOVQ ·a+0(FP), DI
|
||||
MOVQ DI, AX
|
||||
MOVL 40(DI), R10
|
||||
MOVL 12(DI), R12
|
||||
MOVL 44(DI), BP
|
||||
MOVL 16(DI), DX
|
||||
MOVL (DI), R15
|
||||
MOVL 48(DI), R9
|
||||
MOVL 20(DI), SI
|
||||
MOVL 32(DI), R11
|
||||
ADDL DX, R15
|
||||
MOVL 4(DI), R14
|
||||
MOVL 52(DI), R8
|
||||
XORL R15, R9
|
||||
MOVL 24(DI), CX
|
||||
MOVL 8(DI), R13
|
||||
ROLL $16, R9
|
||||
ADDL SI, R14
|
||||
MOVL 36(DI), BX
|
||||
MOVL 56(DI), DI
|
||||
ADDL R9, R11
|
||||
XORL R14, R8
|
||||
ADDL CX, R13
|
||||
XORL R11, DX
|
||||
ROLL $16, R8
|
||||
XORL R13, DI
|
||||
ROLL $12, DX
|
||||
ADDL R8, BX
|
||||
ROLL $16, DI
|
||||
ADDL DX, R15
|
||||
XORL BX, SI
|
||||
ADDL DI, R10
|
||||
XORL R15, R9
|
||||
ROLL $12, SI
|
||||
XORL R10, CX
|
||||
ROLL $8, R9
|
||||
ADDL SI, R14
|
||||
ROLL $12, CX
|
||||
ADDL R9, R11
|
||||
XORL R14, R8
|
||||
ADDL CX, R13
|
||||
XORL R11, DX
|
||||
ROLL $8, R8
|
||||
XORL R13, DI
|
||||
ROLL $7, DX
|
||||
LEAL (BX)(R8*1), BX
|
||||
ROLL $8, DI
|
||||
MOVL DX, tmp0-8(SP)
|
||||
MOVL 28(AX), DX
|
||||
XORL BX, SI
|
||||
MOVL BX, tmp1-4(SP)
|
||||
MOVL R10, BX
|
||||
MOVL 60(AX), R10
|
||||
ROLL $7, SI
|
||||
ADDL DI, BX
|
||||
ADDL DX, R12
|
||||
ADDL SI, R15
|
||||
XORL R12, R10
|
||||
XORL BX, CX
|
||||
ROLL $16, R10
|
||||
ROLL $7, CX
|
||||
ADDL R10, BP
|
||||
ADDL CX, R14
|
||||
XORL BP, DX
|
||||
XORL R14, R9
|
||||
ROLL $12, DX
|
||||
ROLL $16, R9
|
||||
ADDL DX, R12
|
||||
XORL R12, R10
|
||||
ROLL $8, R10
|
||||
ADDL R10, BP
|
||||
XORL R15, R10
|
||||
ROLL $16, R10
|
||||
XORL BP, DX
|
||||
ADDL R9, BP
|
||||
ADDL R10, BX
|
||||
ROLL $7, DX
|
||||
XORL BP, CX
|
||||
XORL BX, SI
|
||||
ROLL $12, SI
|
||||
ADDL SI, R15
|
||||
XORL R15, R10
|
||||
MOVL R15, (AX)
|
||||
ROLL $8, R10
|
||||
ADDL R10, BX
|
||||
MOVL R10, 60(AX)
|
||||
XORL BX, SI
|
||||
MOVD BX, X1
|
||||
ROLL $7, SI
|
||||
ROLL $12, CX
|
||||
ADDL DX, R13
|
||||
XORL R13, R8
|
||||
ADDL CX, R14
|
||||
MOVL SI, 20(AX)
|
||||
ROLL $16, R8
|
||||
XORL R14, R9
|
||||
MOVL R14, 4(AX)
|
||||
ADDL R8, R11
|
||||
ROLL $8, R9
|
||||
XORL R11, DX
|
||||
ADDL R9, BP
|
||||
MOVL R9, 48(AX)
|
||||
ROLL $12, DX
|
||||
XORL BP, CX
|
||||
MOVD BP, X2
|
||||
ADDL DX, R13
|
||||
ROLL $7, CX
|
||||
PUNPCKLLQ X2, X1
|
||||
XORL R13, R8
|
||||
MOVL CX, 24(AX)
|
||||
ROLL $8, R8
|
||||
MOVL R13, 8(AX)
|
||||
ADDL R8, R11
|
||||
XORL R11, DX
|
||||
MOVD R11, X0
|
||||
ROLL $7, DX
|
||||
MOVL DX, 28(AX)
|
||||
MOVL R8, 52(AX)
|
||||
MOVL tmp0-8(SP), SI
|
||||
MOVL tmp1-4(SP), CX
|
||||
ADDL SI, R12
|
||||
XORL R12, DI
|
||||
ROLL $16, DI
|
||||
ADDL DI, CX
|
||||
XORL CX, SI
|
||||
MOVL SI, DX
|
||||
ROLL $12, DX
|
||||
ADDL DX, R12
|
||||
XORL R12, DI
|
||||
MOVL R12, 12(AX)
|
||||
ROLL $8, DI
|
||||
ADDL DI, CX
|
||||
MOVL DI, 56(AX)
|
||||
MOVD CX, X3
|
||||
XORL CX, DX
|
||||
PUNPCKLLQ X3, X0
|
||||
ROLL $7, DX
|
||||
PUNPCKLQDQ X1, X0
|
||||
MOVL DX, 16(AX)
|
||||
MOVUPS X0, 32(AX)
|
||||
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
|
||||
TESTQ DX, DX
|
||||
JE quickend
|
||||
ADDQ SI, DX
|
||||
MOVL $-1, AX
|
||||
lop:
|
||||
MOVBLZX (SI), CX
|
||||
ADDQ $1, SI
|
||||
XORL AX, CX
|
||||
SHRL $8, AX
|
||||
MOVBLZX CX, CX
|
||||
XORL (DI)(CX*4), AX
|
||||
CMPQ SI, DX
|
||||
JNE lop
|
||||
NOTL AX
|
||||
MOVQ AX, ·bngas+32(FP)
|
||||
RET
|
||||
quickend:
|
||||
XORL AX, AX
|
||||
RET
|
||||
|
@ -1,117 +0,0 @@
|
||||
//go:build amd64
|
||||
|
||||
package t544
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"io"
|
||||
)
|
||||
|
||||
type encryptionData struct {
|
||||
tableA [16][2][16][16]byte
|
||||
tableB [16][16]byte
|
||||
tableC [256][6]byte
|
||||
tableD [16]byte
|
||||
tableE [16]byte
|
||||
tableF [15]uint32
|
||||
}
|
||||
|
||||
type state struct {
|
||||
state [16]uint32 // 16
|
||||
orgstate [16]uint32 // 16
|
||||
nr uint8
|
||||
p uint8
|
||||
}
|
||||
|
||||
var crypto = encryptionData{
|
||||
tableA: readData[[16][2][16][16]byte]("table_a.bin"),
|
||||
tableB: readData[[16][16]byte]("table_b.bin"),
|
||||
tableC: readData[[256][6]byte]("table_c.bin"),
|
||||
tableD: readData[[16]byte]("table_d.bin"),
|
||||
tableE: readData[[16]byte]("table_e.bin"),
|
||||
tableF: func() (tab [15]uint32) {
|
||||
f, err := cryptoZip.Open("table_f.bin")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
data, err := io.ReadAll(f)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
for i := range tab {
|
||||
tab[i] = binary.LittleEndian.Uint32(data[i*4 : (i+1)*4])
|
||||
}
|
||||
return
|
||||
}(),
|
||||
}
|
||||
|
||||
func (e *encryptionData) tencentEncryptB(p1 []byte, p2 []uint32) {
|
||||
const c = 10
|
||||
for r := 0; r < 9; r++ {
|
||||
sub_d(&e.tableD, p1)
|
||||
sub_b(p1, p2[r*4:(r+1)*4])
|
||||
sub_c(&e.tableB, p1)
|
||||
sub_e(&e.tableC, p1)
|
||||
}
|
||||
sub_d(&e.tableD, p1)
|
||||
sub_b(p1, p2[(c-1)*4:c*4])
|
||||
sub_c(&e.tableB, p1)
|
||||
sub_a(p1, p2[c*4:(c+1)*4])
|
||||
}
|
||||
|
||||
func (e *encryptionData) tencentEncryptionB(c []byte, m []byte) (out [0x15]byte) {
|
||||
var buf [16]byte
|
||||
w := sub_f(&e.tableE, &e.tableF, &e.tableB)
|
||||
|
||||
for i := range out {
|
||||
if (i & 0xf) == 0 {
|
||||
copy(buf[:], c)
|
||||
e.tencentEncryptB(buf[:], w[:])
|
||||
for j := 15; j >= 0; j-- {
|
||||
c[j]++
|
||||
if c[j] != 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
out[i] = sub_aa(i, &e.tableA, &buf, m)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func tencentEncryptionA(input, key, data []byte) {
|
||||
var s state
|
||||
s.init(key, data, 0, 20)
|
||||
s.encrypt(input)
|
||||
}
|
||||
|
||||
func (c *state) encrypt(data []byte) {
|
||||
bp := 0
|
||||
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]
|
||||
}
|
||||
}
|
||||
var sb [16 * 4]byte
|
||||
for i, v := range c.state {
|
||||
binary.LittleEndian.PutUint32(sb[i*4:(i+1)*4], v)
|
||||
}
|
||||
for c.p != 64 && dataLen != 0 {
|
||||
data[bp] ^= sb[c.p]
|
||||
c.p++
|
||||
bp++
|
||||
dataLen--
|
||||
}
|
||||
if c.p >= 64 {
|
||||
c.p = 0
|
||||
c.orgstate[12]++
|
||||
c.state = c.orgstate
|
||||
}
|
||||
}
|
||||
}
|
@ -1,93 +0,0 @@
|
||||
//go:build amd64
|
||||
|
||||
package t544
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/rc4"
|
||||
"encoding/binary"
|
||||
"math/rand"
|
||||
"unsafe"
|
||||
|
||||
"github.com/Mrs4s/go-cqhttp/internal/encryption"
|
||||
)
|
||||
|
||||
const (
|
||||
keyTable = "$%&()+,-456789:?ABCDEEFGHIJabcdefghijkopqrstuvwxyz"
|
||||
table2 = "!#$%&)+.0123456789:=>?@ABCDEFGKMNabcdefghijkopqrst"
|
||||
)
|
||||
|
||||
var (
|
||||
magic = uint64(0x6EEDCF0DC4675540)
|
||||
key1 = [8]byte{'a', '$', '(', 'e', 'T', '7', '*', '@'}
|
||||
key2 = [8]byte{'&', 'O', '9', '!', '>', '6', 'X', ')'}
|
||||
)
|
||||
|
||||
func init() {
|
||||
if canusesse2 {
|
||||
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 {
|
||||
curr %= 1000000
|
||||
input = append(input, []byte{byte(curr >> 24), byte(curr >> 16), byte(curr >> 8), byte(curr)}...)
|
||||
var kt [4 + 32 + 4]byte
|
||||
r := rand.New(rand.NewSource(curr))
|
||||
for i := 0; i < 2; i++ {
|
||||
kt[i] = keyTable[r.Int()%0x32] + 50
|
||||
}
|
||||
kt[2] = kt[1] + 20
|
||||
kt[3] = kt[2] + 20
|
||||
key3 := kt[4 : 4+10]
|
||||
k3calc := key3[2:10]
|
||||
copy(k3calc, key1[:4])
|
||||
for i := 0; i < 4; i++ {
|
||||
k3calc[4+i] = key2[i] ^ kt[i]
|
||||
}
|
||||
key3[0], key3[1] = k3calc[6], k3calc[7]
|
||||
key3 = key3[:8]
|
||||
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))[:])
|
||||
tencentEncryptionA(input, kt[4:4+32], crcData[4:4+8])
|
||||
result := md5.Sum(input)
|
||||
crcData[2] = 1
|
||||
crcData[4] = 1
|
||||
copy(crcData[5:9], kt[:4])
|
||||
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))[:])
|
||||
crcData[0] = kt[4+32]
|
||||
crcData[1] = kt[4+32+3]
|
||||
nonce := uint32(r.Int() ^ r.Int() ^ r.Int())
|
||||
on := kt[:16]
|
||||
binary.BigEndian.PutUint32(on[:4], nonce)
|
||||
copy(on[4:8], on[:4])
|
||||
copy(on[8:16], on[:8])
|
||||
ts.transformEncode(&crcData)
|
||||
encryptedData := crypto.tencentEncryptionB(on, crcData[:])
|
||||
ts.transformDecode(&encryptedData)
|
||||
output := kt[:39]
|
||||
output[0] = 0x0C
|
||||
output[1] = 0x05
|
||||
binary.BigEndian.PutUint32(output[2:6], nonce)
|
||||
copy(output[6:27], encryptedData[:])
|
||||
binary.LittleEndian.PutUint32(output[27:31], 0)
|
||||
output[31] = table2[r.Int()%0x32]
|
||||
output[32] = table2[r.Int()%0x32]
|
||||
addition := r.Int() % 9
|
||||
for addition&1 == 0 {
|
||||
addition = r.Int() % 9
|
||||
}
|
||||
output[33] = output[31] + byte(addition)
|
||||
output[34] = output[32] + byte(9-addition) + 1
|
||||
binary.LittleEndian.PutUint32(output[35:39], 0)
|
||||
return output
|
||||
}
|
@ -1,7 +0,0 @@
|
||||
//go:build !amd64
|
||||
|
||||
package t544
|
||||
|
||||
func init() {
|
||||
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
//go:build amd64
|
||||
|
||||
package t544
|
||||
|
||||
type transformer struct {
|
||||
encode [32][16]byte
|
||||
decode [32][16]byte
|
||||
}
|
||||
|
||||
func (ts *transformer) transformEncode(bArr *[0x15]byte) {
|
||||
transformInner(bArr, &ts.encode)
|
||||
}
|
||||
|
||||
func (ts *transformer) transformDecode(bArr *[0x15]byte) {
|
||||
transformInner(bArr, &ts.decode)
|
||||
}
|
||||
|
||||
var ts = transformer{
|
||||
encode: readData[[32][16]byte]("encode.bin"),
|
||||
decode: readData[[32][16]byte]("decode.bin"),
|
||||
}
|
@ -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)
|
||||
|
@ -35,6 +35,7 @@ type Account struct {
|
||||
ReLogin *Reconnect `yaml:"relogin"`
|
||||
UseSSOAddress bool `yaml:"use-sso-address"`
|
||||
AllowTempSession bool `yaml:"allow-temp-session"`
|
||||
SignServer string `yaml:"sign-server"`
|
||||
}
|
||||
|
||||
// Config 总配置文件
|
||||
@ -56,6 +57,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 {
|
||||
|
@ -16,6 +16,15 @@ account: # 账号相关
|
||||
# 是否允许发送临时会话消息
|
||||
allow-temp-session: false
|
||||
|
||||
# 数据包的签名服务器
|
||||
# 兼容 https://github.com/fuqiuluo/unidbg-fetch-qsign
|
||||
# 如果遇到 登录 45 错误, 或者发送信息风控的话需要填入一个服务器
|
||||
# 示例:
|
||||
# sign-server: 'http://127.0.0.1:8080' # 本地签名服务器
|
||||
# sign-server: 'https://signserver.example.com' # 线上签名服务器
|
||||
# 服务器可使用docker在本地搭建或者使用他人开放的服务
|
||||
sign-server: '-'
|
||||
|
||||
heartbeat:
|
||||
# 心跳频率, 单位秒
|
||||
# -1 为关闭心跳
|
||||
@ -45,6 +54,8 @@ message:
|
||||
skip-mime-scan: false
|
||||
# 是否自动转换 WebP 图片
|
||||
convert-webp-image: false
|
||||
# http超时时间
|
||||
http-timeout: 0
|
||||
|
||||
output:
|
||||
# 日志等级 trace,debug,info,warn,error
|
||||
|
78
pkg/onebot/attr.go
Normal file
78
pkg/onebot/attr.go
Normal 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
31
pkg/onebot/kind_string.go
Normal 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
355
pkg/onebot/value.go
Normal 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()))
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
#!/bin/sh
|
||||
echo "Start GOCQHTTP~~~"
|
||||
|
||||
cp -f config.yml /tmp/config.yml
|
||||
cp -f device.json /tmp/device.json
|
||||
./go-cqhttp -w="/tmp/" faststart
|
||||
#!/usr/bin/env bash
|
||||
function index.main_handler() {
|
||||
echo "Start GOCQHTTP~~~"
|
||||
cp -f config.yml /tmp/config.yml
|
||||
cp -f device.json /tmp/device.json
|
||||
./go-cqhttp -w="/tmp/" faststart
|
||||
}
|
||||
index.main_handler
|
||||
|
Reference in New Issue
Block a user