update protobuf

This commit is contained in:
yincong
2026-05-08 12:33:08 +08:00
parent 50e7dd960e
commit 0070aeaa33
10 changed files with 1471 additions and 289 deletions
+110
View File
@@ -0,0 +1,110 @@
package main
import (
"crypto/rand"
"encoding/hex"
"fmt"
mathrand "math/rand"
"strconv"
"time"
"github.com/yincongcyincong/weixin-macos/onebot/proto/wxproto"
"google.golang.org/protobuf/encoding/protowire"
"google.golang.org/protobuf/proto"
)
// BuildImgMsgProto 构建发送图片消息的protobuf并返回hex编码的字符串
func BuildImgMsgProto(sender, targetId, cdnKey, aesKey, md5Key string) (string, error) {
// 生成16字节随机client_proof (模拟JS的generateBytes(16))
clientProof := make([]byte, 16)
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
randBytes := make([]byte, 16)
rand.Read(randBytes)
for i := range clientProof {
clientProof[i] = chars[int(randBytes[i])%len(chars)]
}
// 生成5字节varint范围的msgId (2^28 ~ 2^35-1)
msgId := mathrand.Int63n(1<<35-1<<28) + (1 << 28)
// header.unknown4 的值: 从 [0xAF, 0xAC, 0x90, 0x93, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01] 解码
// = -228321745 (signed int64)
const headerUnknown4 int64 = -228321745
// client_msg_id: targetId_timestamp_160_xwechat_3
timestamp := time.Now().Unix()
clientMsgId := targetId + "_" + strconv.FormatInt(timestamp, 10) + "_160_xwechat_3"
// xml内容
xmlContent := []byte("<msgsource><alnode><fr>1</fr></alnode></msgsource>")
msg := &wxproto.WxSendImgMsg{
Header: &wxproto.ImgMsgHeader{
Flag: []byte{0x00},
MsgId: msgId,
ClientProof: clientProof,
Unknown4: headerUnknown4,
SysInfo: []byte("UnifiedPCMac 26 arm64"),
Unknown6: 304,
},
ClientMsgId: &wxproto.WxString{Value: clientMsgId},
Sender: &wxproto.WxString{Value: sender},
Receiver: &wxproto.WxString{Value: targetId},
Unknown5: 1524,
// MsgType: 0, // proto3不会序列化0值,需要手动追加
Unknown7: 1524,
// Unknown8: 手动追加 [0x42, 0x04, 0x08, 0x00, 0x12, 0x00]
Unknown9: 3,
Xml: xmlContent,
Unknown11: 1,
Unknown12: 2,
// Unknown13: 0, // 需要手动追加
CdnKey: []byte(cdnKey),
CdnKey2: []byte(cdnKey),
AesKey: []byte(aesKey),
Unknown18: 1,
Unknown19: 2559,
Unknown20: 2559,
CdnKey3: []byte(cdnKey),
Unknown22: 1524,
Unknown23: 104,
Unknown24: 58,
AesKey2: []byte(aesKey),
Md5Key: []byte(md5Key),
Unknown28: 779219929,
// Unknown30: 0, // 需要手动追加
// Unknown36: 0, // 需要手动追加
// Unknown41: 0, // 需要手动追加
}
data, err := proto.Marshal(msg)
if err != nil {
return "", fmt.Errorf("marshal img proto failed: %w", err)
}
// 手动追加proto3不会序列化的0值字段
// field 6 (msg_type=0): tag=0x30, value=0x00
data = appendZeroVarintField(data, 6)
// field 8 (ImgMsgExtra with field1=0, field2=""): [0x42, 0x04, 0x08, 0x00, 0x12, 0x00]
data = append(data, 0x42, 0x04, 0x08, 0x00, 0x12, 0x00)
// field 13 (unknown13=0): tag=0x68, value=0x00
data = appendZeroVarintField(data, 13)
// field 30 (unknown30=0): tag=[0xF0, 0x01], value=0x00
data = appendZeroVarintField(data, 30)
// field 36 (unknown36=0): tag=[0xA0, 0x02], value=0x00
data = appendZeroVarintField(data, 36)
// field 41 (unknown41=0): tag=[0xC8, 0x02], value=0x00
data = appendZeroVarintField(data, 41)
// 追加尾部的 \x00 字节
data = append(data, 0x00)
return hex.EncodeToString(data), nil
}
// appendZeroVarintField 追加一个值为0的varint字段
func appendZeroVarintField(data []byte, fieldNum protowire.Number) []byte {
data = protowire.AppendTag(data, fieldNum, protowire.VarintType)
data = protowire.AppendVarint(data, 0)
return data
}
+5 -3
View File
@@ -22,6 +22,7 @@ var (
userID2NicknameMap sync.Map
userID2FileMsgMap sync.Map
videoDurationMap sync.Map // targetId -> int32(duration seconds)
)
type WechatMessage struct {
@@ -57,9 +58,10 @@ type SendMsg struct {
FilePath string
FileType int
CdnKey string
Md5Key string
VideoId string
CdnKey string
Md5Key string
VideoId string
Duration int32
}
// SendRequest 请求结构体
+536
View File
@@ -0,0 +1,536 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.11
// protoc v3.5.1
// source: proto/wxproto/img_msg.proto
package wxproto
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// 发送图片消息的protobuf结构
type WxSendImgMsg struct {
state protoimpl.MessageState `protogen:"open.v1"`
Header *ImgMsgHeader `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"`
ClientMsgId *WxString `protobuf:"bytes,2,opt,name=client_msg_id,json=clientMsgId,proto3" json:"client_msg_id,omitempty"`
Sender *WxString `protobuf:"bytes,3,opt,name=sender,proto3" json:"sender,omitempty"`
Receiver *WxString `protobuf:"bytes,4,opt,name=receiver,proto3" json:"receiver,omitempty"`
Unknown5 int32 `protobuf:"varint,5,opt,name=unknown5,proto3" json:"unknown5,omitempty"`
MsgType int32 `protobuf:"varint,6,opt,name=msg_type,json=msgType,proto3" json:"msg_type,omitempty"`
Unknown7 int32 `protobuf:"varint,7,opt,name=unknown7,proto3" json:"unknown7,omitempty"`
Unknown8 *ImgMsgExtra `protobuf:"bytes,8,opt,name=unknown8,proto3" json:"unknown8,omitempty"`
Unknown9 int32 `protobuf:"varint,9,opt,name=unknown9,proto3" json:"unknown9,omitempty"`
Xml []byte `protobuf:"bytes,10,opt,name=xml,proto3" json:"xml,omitempty"`
Unknown11 int32 `protobuf:"varint,11,opt,name=unknown11,proto3" json:"unknown11,omitempty"`
Unknown12 int32 `protobuf:"varint,12,opt,name=unknown12,proto3" json:"unknown12,omitempty"`
Unknown13 int32 `protobuf:"varint,13,opt,name=unknown13,proto3" json:"unknown13,omitempty"`
// field 14 skipped
CdnKey []byte `protobuf:"bytes,15,opt,name=cdn_key,json=cdnKey,proto3" json:"cdn_key,omitempty"`
CdnKey2 []byte `protobuf:"bytes,16,opt,name=cdn_key2,json=cdnKey2,proto3" json:"cdn_key2,omitempty"`
AesKey []byte `protobuf:"bytes,17,opt,name=aes_key,json=aesKey,proto3" json:"aes_key,omitempty"`
Unknown18 int32 `protobuf:"varint,18,opt,name=unknown18,proto3" json:"unknown18,omitempty"`
Unknown19 int32 `protobuf:"varint,19,opt,name=unknown19,proto3" json:"unknown19,omitempty"`
Unknown20 int32 `protobuf:"varint,20,opt,name=unknown20,proto3" json:"unknown20,omitempty"`
CdnKey3 []byte `protobuf:"bytes,21,opt,name=cdn_key3,json=cdnKey3,proto3" json:"cdn_key3,omitempty"`
Unknown22 int32 `protobuf:"varint,22,opt,name=unknown22,proto3" json:"unknown22,omitempty"`
Unknown23 int32 `protobuf:"varint,23,opt,name=unknown23,proto3" json:"unknown23,omitempty"`
Unknown24 int32 `protobuf:"varint,24,opt,name=unknown24,proto3" json:"unknown24,omitempty"`
AesKey2 []byte `protobuf:"bytes,25,opt,name=aes_key2,json=aesKey2,proto3" json:"aes_key2,omitempty"`
// field 26 skipped
Md5Key []byte `protobuf:"bytes,27,opt,name=md5_key,json=md5Key,proto3" json:"md5_key,omitempty"`
Unknown28 int64 `protobuf:"varint,28,opt,name=unknown28,proto3" json:"unknown28,omitempty"`
// field 29 skipped
Unknown30 int32 `protobuf:"varint,30,opt,name=unknown30,proto3" json:"unknown30,omitempty"`
// fields 31-35 skipped
Unknown36 int32 `protobuf:"varint,36,opt,name=unknown36,proto3" json:"unknown36,omitempty"`
// fields 37-40 skipped
Unknown41 int32 `protobuf:"varint,41,opt,name=unknown41,proto3" json:"unknown41,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *WxSendImgMsg) Reset() {
*x = WxSendImgMsg{}
mi := &file_proto_wxproto_img_msg_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *WxSendImgMsg) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*WxSendImgMsg) ProtoMessage() {}
func (x *WxSendImgMsg) ProtoReflect() protoreflect.Message {
mi := &file_proto_wxproto_img_msg_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use WxSendImgMsg.ProtoReflect.Descriptor instead.
func (*WxSendImgMsg) Descriptor() ([]byte, []int) {
return file_proto_wxproto_img_msg_proto_rawDescGZIP(), []int{0}
}
func (x *WxSendImgMsg) GetHeader() *ImgMsgHeader {
if x != nil {
return x.Header
}
return nil
}
func (x *WxSendImgMsg) GetClientMsgId() *WxString {
if x != nil {
return x.ClientMsgId
}
return nil
}
func (x *WxSendImgMsg) GetSender() *WxString {
if x != nil {
return x.Sender
}
return nil
}
func (x *WxSendImgMsg) GetReceiver() *WxString {
if x != nil {
return x.Receiver
}
return nil
}
func (x *WxSendImgMsg) GetUnknown5() int32 {
if x != nil {
return x.Unknown5
}
return 0
}
func (x *WxSendImgMsg) GetMsgType() int32 {
if x != nil {
return x.MsgType
}
return 0
}
func (x *WxSendImgMsg) GetUnknown7() int32 {
if x != nil {
return x.Unknown7
}
return 0
}
func (x *WxSendImgMsg) GetUnknown8() *ImgMsgExtra {
if x != nil {
return x.Unknown8
}
return nil
}
func (x *WxSendImgMsg) GetUnknown9() int32 {
if x != nil {
return x.Unknown9
}
return 0
}
func (x *WxSendImgMsg) GetXml() []byte {
if x != nil {
return x.Xml
}
return nil
}
func (x *WxSendImgMsg) GetUnknown11() int32 {
if x != nil {
return x.Unknown11
}
return 0
}
func (x *WxSendImgMsg) GetUnknown12() int32 {
if x != nil {
return x.Unknown12
}
return 0
}
func (x *WxSendImgMsg) GetUnknown13() int32 {
if x != nil {
return x.Unknown13
}
return 0
}
func (x *WxSendImgMsg) GetCdnKey() []byte {
if x != nil {
return x.CdnKey
}
return nil
}
func (x *WxSendImgMsg) GetCdnKey2() []byte {
if x != nil {
return x.CdnKey2
}
return nil
}
func (x *WxSendImgMsg) GetAesKey() []byte {
if x != nil {
return x.AesKey
}
return nil
}
func (x *WxSendImgMsg) GetUnknown18() int32 {
if x != nil {
return x.Unknown18
}
return 0
}
func (x *WxSendImgMsg) GetUnknown19() int32 {
if x != nil {
return x.Unknown19
}
return 0
}
func (x *WxSendImgMsg) GetUnknown20() int32 {
if x != nil {
return x.Unknown20
}
return 0
}
func (x *WxSendImgMsg) GetCdnKey3() []byte {
if x != nil {
return x.CdnKey3
}
return nil
}
func (x *WxSendImgMsg) GetUnknown22() int32 {
if x != nil {
return x.Unknown22
}
return 0
}
func (x *WxSendImgMsg) GetUnknown23() int32 {
if x != nil {
return x.Unknown23
}
return 0
}
func (x *WxSendImgMsg) GetUnknown24() int32 {
if x != nil {
return x.Unknown24
}
return 0
}
func (x *WxSendImgMsg) GetAesKey2() []byte {
if x != nil {
return x.AesKey2
}
return nil
}
func (x *WxSendImgMsg) GetMd5Key() []byte {
if x != nil {
return x.Md5Key
}
return nil
}
func (x *WxSendImgMsg) GetUnknown28() int64 {
if x != nil {
return x.Unknown28
}
return 0
}
func (x *WxSendImgMsg) GetUnknown30() int32 {
if x != nil {
return x.Unknown30
}
return 0
}
func (x *WxSendImgMsg) GetUnknown36() int32 {
if x != nil {
return x.Unknown36
}
return 0
}
func (x *WxSendImgMsg) GetUnknown41() int32 {
if x != nil {
return x.Unknown41
}
return 0
}
type ImgMsgHeader struct {
state protoimpl.MessageState `protogen:"open.v1"`
Flag []byte `protobuf:"bytes,1,opt,name=flag,proto3" json:"flag,omitempty"`
MsgId int64 `protobuf:"varint,2,opt,name=msg_id,json=msgId,proto3" json:"msg_id,omitempty"`
ClientProof []byte `protobuf:"bytes,3,opt,name=client_proof,json=clientProof,proto3" json:"client_proof,omitempty"`
Unknown4 int64 `protobuf:"varint,4,opt,name=unknown4,proto3" json:"unknown4,omitempty"`
SysInfo []byte `protobuf:"bytes,5,opt,name=sys_info,json=sysInfo,proto3" json:"sys_info,omitempty"`
Unknown6 int32 `protobuf:"varint,6,opt,name=unknown6,proto3" json:"unknown6,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ImgMsgHeader) Reset() {
*x = ImgMsgHeader{}
mi := &file_proto_wxproto_img_msg_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ImgMsgHeader) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ImgMsgHeader) ProtoMessage() {}
func (x *ImgMsgHeader) ProtoReflect() protoreflect.Message {
mi := &file_proto_wxproto_img_msg_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ImgMsgHeader.ProtoReflect.Descriptor instead.
func (*ImgMsgHeader) Descriptor() ([]byte, []int) {
return file_proto_wxproto_img_msg_proto_rawDescGZIP(), []int{1}
}
func (x *ImgMsgHeader) GetFlag() []byte {
if x != nil {
return x.Flag
}
return nil
}
func (x *ImgMsgHeader) GetMsgId() int64 {
if x != nil {
return x.MsgId
}
return 0
}
func (x *ImgMsgHeader) GetClientProof() []byte {
if x != nil {
return x.ClientProof
}
return nil
}
func (x *ImgMsgHeader) GetUnknown4() int64 {
if x != nil {
return x.Unknown4
}
return 0
}
func (x *ImgMsgHeader) GetSysInfo() []byte {
if x != nil {
return x.SysInfo
}
return nil
}
func (x *ImgMsgHeader) GetUnknown6() int32 {
if x != nil {
return x.Unknown6
}
return 0
}
type ImgMsgExtra struct {
state protoimpl.MessageState `protogen:"open.v1"`
Field1 int32 `protobuf:"varint,1,opt,name=field1,proto3" json:"field1,omitempty"`
Field2 []byte `protobuf:"bytes,2,opt,name=field2,proto3" json:"field2,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *ImgMsgExtra) Reset() {
*x = ImgMsgExtra{}
mi := &file_proto_wxproto_img_msg_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *ImgMsgExtra) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ImgMsgExtra) ProtoMessage() {}
func (x *ImgMsgExtra) ProtoReflect() protoreflect.Message {
mi := &file_proto_wxproto_img_msg_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use ImgMsgExtra.ProtoReflect.Descriptor instead.
func (*ImgMsgExtra) Descriptor() ([]byte, []int) {
return file_proto_wxproto_img_msg_proto_rawDescGZIP(), []int{2}
}
func (x *ImgMsgExtra) GetField1() int32 {
if x != nil {
return x.Field1
}
return 0
}
func (x *ImgMsgExtra) GetField2() []byte {
if x != nil {
return x.Field2
}
return nil
}
var File_proto_wxproto_img_msg_proto protoreflect.FileDescriptor
const file_proto_wxproto_img_msg_proto_rawDesc = "" +
"\n" +
"\x1bproto/wxproto/img_msg.proto\x12\awxproto\x1a\x1aproto/wxproto/wx_msg.proto\"\xa3\a\n" +
"\fWxSendImgMsg\x12-\n" +
"\x06header\x18\x01 \x01(\v2\x15.wxproto.ImgMsgHeaderR\x06header\x125\n" +
"\rclient_msg_id\x18\x02 \x01(\v2\x11.wxproto.WxStringR\vclientMsgId\x12)\n" +
"\x06sender\x18\x03 \x01(\v2\x11.wxproto.WxStringR\x06sender\x12-\n" +
"\breceiver\x18\x04 \x01(\v2\x11.wxproto.WxStringR\breceiver\x12\x1a\n" +
"\bunknown5\x18\x05 \x01(\x05R\bunknown5\x12\x19\n" +
"\bmsg_type\x18\x06 \x01(\x05R\amsgType\x12\x1a\n" +
"\bunknown7\x18\a \x01(\x05R\bunknown7\x120\n" +
"\bunknown8\x18\b \x01(\v2\x14.wxproto.ImgMsgExtraR\bunknown8\x12\x1a\n" +
"\bunknown9\x18\t \x01(\x05R\bunknown9\x12\x10\n" +
"\x03xml\x18\n" +
" \x01(\fR\x03xml\x12\x1c\n" +
"\tunknown11\x18\v \x01(\x05R\tunknown11\x12\x1c\n" +
"\tunknown12\x18\f \x01(\x05R\tunknown12\x12\x1c\n" +
"\tunknown13\x18\r \x01(\x05R\tunknown13\x12\x17\n" +
"\acdn_key\x18\x0f \x01(\fR\x06cdnKey\x12\x19\n" +
"\bcdn_key2\x18\x10 \x01(\fR\acdnKey2\x12\x17\n" +
"\aaes_key\x18\x11 \x01(\fR\x06aesKey\x12\x1c\n" +
"\tunknown18\x18\x12 \x01(\x05R\tunknown18\x12\x1c\n" +
"\tunknown19\x18\x13 \x01(\x05R\tunknown19\x12\x1c\n" +
"\tunknown20\x18\x14 \x01(\x05R\tunknown20\x12\x19\n" +
"\bcdn_key3\x18\x15 \x01(\fR\acdnKey3\x12\x1c\n" +
"\tunknown22\x18\x16 \x01(\x05R\tunknown22\x12\x1c\n" +
"\tunknown23\x18\x17 \x01(\x05R\tunknown23\x12\x1c\n" +
"\tunknown24\x18\x18 \x01(\x05R\tunknown24\x12\x19\n" +
"\baes_key2\x18\x19 \x01(\fR\aaesKey2\x12\x17\n" +
"\amd5_key\x18\x1b \x01(\fR\x06md5Key\x12\x1c\n" +
"\tunknown28\x18\x1c \x01(\x03R\tunknown28\x12\x1c\n" +
"\tunknown30\x18\x1e \x01(\x05R\tunknown30\x12\x1c\n" +
"\tunknown36\x18$ \x01(\x05R\tunknown36\x12\x1c\n" +
"\tunknown41\x18) \x01(\x05R\tunknown41\"\xaf\x01\n" +
"\fImgMsgHeader\x12\x12\n" +
"\x04flag\x18\x01 \x01(\fR\x04flag\x12\x15\n" +
"\x06msg_id\x18\x02 \x01(\x03R\x05msgId\x12!\n" +
"\fclient_proof\x18\x03 \x01(\fR\vclientProof\x12\x1a\n" +
"\bunknown4\x18\x04 \x01(\x03R\bunknown4\x12\x19\n" +
"\bsys_info\x18\x05 \x01(\fR\asysInfo\x12\x1a\n" +
"\bunknown6\x18\x06 \x01(\x05R\bunknown6\"=\n" +
"\vImgMsgExtra\x12\x16\n" +
"\x06field1\x18\x01 \x01(\x05R\x06field1\x12\x16\n" +
"\x06field2\x18\x02 \x01(\fR\x06field2B>Z<github.com/yincongcyincong/weixin-macos/onebot/proto/wxprotob\x06proto3"
var (
file_proto_wxproto_img_msg_proto_rawDescOnce sync.Once
file_proto_wxproto_img_msg_proto_rawDescData []byte
)
func file_proto_wxproto_img_msg_proto_rawDescGZIP() []byte {
file_proto_wxproto_img_msg_proto_rawDescOnce.Do(func() {
file_proto_wxproto_img_msg_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_proto_wxproto_img_msg_proto_rawDesc), len(file_proto_wxproto_img_msg_proto_rawDesc)))
})
return file_proto_wxproto_img_msg_proto_rawDescData
}
var file_proto_wxproto_img_msg_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_proto_wxproto_img_msg_proto_goTypes = []any{
(*WxSendImgMsg)(nil), // 0: wxproto.WxSendImgMsg
(*ImgMsgHeader)(nil), // 1: wxproto.ImgMsgHeader
(*ImgMsgExtra)(nil), // 2: wxproto.ImgMsgExtra
(*WxString)(nil), // 3: wxproto.WxString
}
var file_proto_wxproto_img_msg_proto_depIdxs = []int32{
1, // 0: wxproto.WxSendImgMsg.header:type_name -> wxproto.ImgMsgHeader
3, // 1: wxproto.WxSendImgMsg.client_msg_id:type_name -> wxproto.WxString
3, // 2: wxproto.WxSendImgMsg.sender:type_name -> wxproto.WxString
3, // 3: wxproto.WxSendImgMsg.receiver:type_name -> wxproto.WxString
2, // 4: wxproto.WxSendImgMsg.unknown8:type_name -> wxproto.ImgMsgExtra
5, // [5:5] is the sub-list for method output_type
5, // [5:5] is the sub-list for method input_type
5, // [5:5] is the sub-list for extension type_name
5, // [5:5] is the sub-list for extension extendee
0, // [0:5] is the sub-list for field type_name
}
func init() { file_proto_wxproto_img_msg_proto_init() }
func file_proto_wxproto_img_msg_proto_init() {
if File_proto_wxproto_img_msg_proto != nil {
return
}
file_proto_wxproto_wx_msg_proto_init()
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_proto_wxproto_img_msg_proto_rawDesc), len(file_proto_wxproto_img_msg_proto_rawDesc)),
NumEnums: 0,
NumMessages: 3,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_proto_wxproto_img_msg_proto_goTypes,
DependencyIndexes: file_proto_wxproto_img_msg_proto_depIdxs,
MessageInfos: file_proto_wxproto_img_msg_proto_msgTypes,
}.Build()
File_proto_wxproto_img_msg_proto = out.File
file_proto_wxproto_img_msg_proto_goTypes = nil
file_proto_wxproto_img_msg_proto_depIdxs = nil
}
+59
View File
@@ -0,0 +1,59 @@
syntax = "proto3";
package wxproto;
option go_package = "github.com/yincongcyincong/weixin-macos/onebot/proto/wxproto";
import "proto/wxproto/wx_msg.proto";
// 发送图片消息的protobuf结构
message WxSendImgMsg {
ImgMsgHeader header = 1;
WxString client_msg_id = 2;
WxString sender = 3;
WxString receiver = 4;
int32 unknown5 = 5;
int32 msg_type = 6;
int32 unknown7 = 7;
ImgMsgExtra unknown8 = 8;
int32 unknown9 = 9;
bytes xml = 10;
int32 unknown11 = 11;
int32 unknown12 = 12;
int32 unknown13 = 13;
// field 14 skipped
bytes cdn_key = 15;
bytes cdn_key2 = 16;
bytes aes_key = 17;
int32 unknown18 = 18;
int32 unknown19 = 19;
int32 unknown20 = 20;
bytes cdn_key3 = 21;
int32 unknown22 = 22;
int32 unknown23 = 23;
int32 unknown24 = 24;
bytes aes_key2 = 25;
// field 26 skipped
bytes md5_key = 27;
int64 unknown28 = 28;
// field 29 skipped
int32 unknown30 = 30;
// fields 31-35 skipped
int32 unknown36 = 36;
// fields 37-40 skipped
int32 unknown41 = 41;
}
message ImgMsgHeader {
bytes flag = 1;
int64 msg_id = 2;
bytes client_proof = 3;
int64 unknown4 = 4;
bytes sys_info = 5;
int32 unknown6 = 6;
}
message ImgMsgExtra {
int32 field1 = 1;
bytes field2 = 2;
}
+539
View File
@@ -0,0 +1,539 @@
// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// protoc-gen-go v1.36.11
// protoc v3.5.1
// source: proto/wxproto/video_msg.proto
package wxproto
import (
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
reflect "reflect"
sync "sync"
unsafe "unsafe"
)
const (
// Verify that this generated code is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
// Verify that runtime/protoimpl is sufficiently up-to-date.
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
// 发送视频消息的protobuf结构
type WxSendVideoMsg struct {
state protoimpl.MessageState `protogen:"open.v1"`
Header *VideoMsgHeader `protobuf:"bytes,1,opt,name=header,proto3" json:"header,omitempty"`
ClientMsgId []byte `protobuf:"bytes,2,opt,name=client_msg_id,json=clientMsgId,proto3" json:"client_msg_id,omitempty"`
Sender []byte `protobuf:"bytes,3,opt,name=sender,proto3" json:"sender,omitempty"`
Receiver []byte `protobuf:"bytes,4,opt,name=receiver,proto3" json:"receiver,omitempty"`
Unknown5 int32 `protobuf:"varint,5,opt,name=unknown5,proto3" json:"unknown5,omitempty"`
Unknown6 int32 `protobuf:"varint,6,opt,name=unknown6,proto3" json:"unknown6,omitempty"`
Unknown7 *VideoMsgExtra `protobuf:"bytes,7,opt,name=unknown7,proto3" json:"unknown7,omitempty"`
Unknown8 int32 `protobuf:"varint,8,opt,name=unknown8,proto3" json:"unknown8,omitempty"`
Unknown9 int32 `protobuf:"varint,9,opt,name=unknown9,proto3" json:"unknown9,omitempty"`
Unknown10 *VideoMsgExtra `protobuf:"bytes,10,opt,name=unknown10,proto3" json:"unknown10,omitempty"`
Duration int32 `protobuf:"varint,11,opt,name=duration,proto3" json:"duration,omitempty"`
Unknown12 int32 `protobuf:"varint,12,opt,name=unknown12,proto3" json:"unknown12,omitempty"`
Unknown13 int32 `protobuf:"varint,13,opt,name=unknown13,proto3" json:"unknown13,omitempty"`
Unknown14 int32 `protobuf:"varint,14,opt,name=unknown14,proto3" json:"unknown14,omitempty"`
Xml []byte `protobuf:"bytes,15,opt,name=xml,proto3" json:"xml,omitempty"`
CdnKey []byte `protobuf:"bytes,16,opt,name=cdn_key,json=cdnKey,proto3" json:"cdn_key,omitempty"`
AesKey []byte `protobuf:"bytes,17,opt,name=aes_key,json=aesKey,proto3" json:"aes_key,omitempty"`
Unknown18 int32 `protobuf:"varint,18,opt,name=unknown18,proto3" json:"unknown18,omitempty"`
CdnKey2 []byte `protobuf:"bytes,19,opt,name=cdn_key2,json=cdnKey2,proto3" json:"cdn_key2,omitempty"`
Unknown20 int32 `protobuf:"varint,20,opt,name=unknown20,proto3" json:"unknown20,omitempty"`
Unknown21 int32 `protobuf:"varint,21,opt,name=unknown21,proto3" json:"unknown21,omitempty"`
Unknown22 int32 `protobuf:"varint,22,opt,name=unknown22,proto3" json:"unknown22,omitempty"`
AesKey2 []byte `protobuf:"bytes,23,opt,name=aes_key2,json=aesKey2,proto3" json:"aes_key2,omitempty"`
// fields 24-25 skipped
Md5Key []byte `protobuf:"bytes,26,opt,name=md5_key,json=md5Key,proto3" json:"md5_key,omitempty"`
// fields 27-36 skipped
VideoId []byte `protobuf:"bytes,37,opt,name=video_id,json=videoId,proto3" json:"video_id,omitempty"`
Unknown38 int32 `protobuf:"varint,38,opt,name=unknown38,proto3" json:"unknown38,omitempty"`
// fields 39-47 skipped
Md5Key2 []byte `protobuf:"bytes,48,opt,name=md5_key2,json=md5Key2,proto3" json:"md5_key2,omitempty"`
CdnKey3 []byte `protobuf:"bytes,49,opt,name=cdn_key3,json=cdnKey3,proto3" json:"cdn_key3,omitempty"`
AesKey3 []byte `protobuf:"bytes,50,opt,name=aes_key3,json=aesKey3,proto3" json:"aes_key3,omitempty"`
Unknown51 int32 `protobuf:"varint,51,opt,name=unknown51,proto3" json:"unknown51,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *WxSendVideoMsg) Reset() {
*x = WxSendVideoMsg{}
mi := &file_proto_wxproto_video_msg_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *WxSendVideoMsg) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*WxSendVideoMsg) ProtoMessage() {}
func (x *WxSendVideoMsg) ProtoReflect() protoreflect.Message {
mi := &file_proto_wxproto_video_msg_proto_msgTypes[0]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use WxSendVideoMsg.ProtoReflect.Descriptor instead.
func (*WxSendVideoMsg) Descriptor() ([]byte, []int) {
return file_proto_wxproto_video_msg_proto_rawDescGZIP(), []int{0}
}
func (x *WxSendVideoMsg) GetHeader() *VideoMsgHeader {
if x != nil {
return x.Header
}
return nil
}
func (x *WxSendVideoMsg) GetClientMsgId() []byte {
if x != nil {
return x.ClientMsgId
}
return nil
}
func (x *WxSendVideoMsg) GetSender() []byte {
if x != nil {
return x.Sender
}
return nil
}
func (x *WxSendVideoMsg) GetReceiver() []byte {
if x != nil {
return x.Receiver
}
return nil
}
func (x *WxSendVideoMsg) GetUnknown5() int32 {
if x != nil {
return x.Unknown5
}
return 0
}
func (x *WxSendVideoMsg) GetUnknown6() int32 {
if x != nil {
return x.Unknown6
}
return 0
}
func (x *WxSendVideoMsg) GetUnknown7() *VideoMsgExtra {
if x != nil {
return x.Unknown7
}
return nil
}
func (x *WxSendVideoMsg) GetUnknown8() int32 {
if x != nil {
return x.Unknown8
}
return 0
}
func (x *WxSendVideoMsg) GetUnknown9() int32 {
if x != nil {
return x.Unknown9
}
return 0
}
func (x *WxSendVideoMsg) GetUnknown10() *VideoMsgExtra {
if x != nil {
return x.Unknown10
}
return nil
}
func (x *WxSendVideoMsg) GetDuration() int32 {
if x != nil {
return x.Duration
}
return 0
}
func (x *WxSendVideoMsg) GetUnknown12() int32 {
if x != nil {
return x.Unknown12
}
return 0
}
func (x *WxSendVideoMsg) GetUnknown13() int32 {
if x != nil {
return x.Unknown13
}
return 0
}
func (x *WxSendVideoMsg) GetUnknown14() int32 {
if x != nil {
return x.Unknown14
}
return 0
}
func (x *WxSendVideoMsg) GetXml() []byte {
if x != nil {
return x.Xml
}
return nil
}
func (x *WxSendVideoMsg) GetCdnKey() []byte {
if x != nil {
return x.CdnKey
}
return nil
}
func (x *WxSendVideoMsg) GetAesKey() []byte {
if x != nil {
return x.AesKey
}
return nil
}
func (x *WxSendVideoMsg) GetUnknown18() int32 {
if x != nil {
return x.Unknown18
}
return 0
}
func (x *WxSendVideoMsg) GetCdnKey2() []byte {
if x != nil {
return x.CdnKey2
}
return nil
}
func (x *WxSendVideoMsg) GetUnknown20() int32 {
if x != nil {
return x.Unknown20
}
return 0
}
func (x *WxSendVideoMsg) GetUnknown21() int32 {
if x != nil {
return x.Unknown21
}
return 0
}
func (x *WxSendVideoMsg) GetUnknown22() int32 {
if x != nil {
return x.Unknown22
}
return 0
}
func (x *WxSendVideoMsg) GetAesKey2() []byte {
if x != nil {
return x.AesKey2
}
return nil
}
func (x *WxSendVideoMsg) GetMd5Key() []byte {
if x != nil {
return x.Md5Key
}
return nil
}
func (x *WxSendVideoMsg) GetVideoId() []byte {
if x != nil {
return x.VideoId
}
return nil
}
func (x *WxSendVideoMsg) GetUnknown38() int32 {
if x != nil {
return x.Unknown38
}
return 0
}
func (x *WxSendVideoMsg) GetMd5Key2() []byte {
if x != nil {
return x.Md5Key2
}
return nil
}
func (x *WxSendVideoMsg) GetCdnKey3() []byte {
if x != nil {
return x.CdnKey3
}
return nil
}
func (x *WxSendVideoMsg) GetAesKey3() []byte {
if x != nil {
return x.AesKey3
}
return nil
}
func (x *WxSendVideoMsg) GetUnknown51() int32 {
if x != nil {
return x.Unknown51
}
return 0
}
type VideoMsgHeader struct {
state protoimpl.MessageState `protogen:"open.v1"`
Flag []byte `protobuf:"bytes,1,opt,name=flag,proto3" json:"flag,omitempty"`
MsgId int64 `protobuf:"varint,2,opt,name=msg_id,json=msgId,proto3" json:"msg_id,omitempty"`
ClientProof []byte `protobuf:"bytes,3,opt,name=client_proof,json=clientProof,proto3" json:"client_proof,omitempty"`
Unknown4 int64 `protobuf:"varint,4,opt,name=unknown4,proto3" json:"unknown4,omitempty"`
SysInfo []byte `protobuf:"bytes,5,opt,name=sys_info,json=sysInfo,proto3" json:"sys_info,omitempty"`
Unknown6 int32 `protobuf:"varint,6,opt,name=unknown6,proto3" json:"unknown6,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *VideoMsgHeader) Reset() {
*x = VideoMsgHeader{}
mi := &file_proto_wxproto_video_msg_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *VideoMsgHeader) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*VideoMsgHeader) ProtoMessage() {}
func (x *VideoMsgHeader) ProtoReflect() protoreflect.Message {
mi := &file_proto_wxproto_video_msg_proto_msgTypes[1]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use VideoMsgHeader.ProtoReflect.Descriptor instead.
func (*VideoMsgHeader) Descriptor() ([]byte, []int) {
return file_proto_wxproto_video_msg_proto_rawDescGZIP(), []int{1}
}
func (x *VideoMsgHeader) GetFlag() []byte {
if x != nil {
return x.Flag
}
return nil
}
func (x *VideoMsgHeader) GetMsgId() int64 {
if x != nil {
return x.MsgId
}
return 0
}
func (x *VideoMsgHeader) GetClientProof() []byte {
if x != nil {
return x.ClientProof
}
return nil
}
func (x *VideoMsgHeader) GetUnknown4() int64 {
if x != nil {
return x.Unknown4
}
return 0
}
func (x *VideoMsgHeader) GetSysInfo() []byte {
if x != nil {
return x.SysInfo
}
return nil
}
func (x *VideoMsgHeader) GetUnknown6() int32 {
if x != nil {
return x.Unknown6
}
return 0
}
type VideoMsgExtra struct {
state protoimpl.MessageState `protogen:"open.v1"`
Field1 int32 `protobuf:"varint,1,opt,name=field1,proto3" json:"field1,omitempty"`
Field2 []byte `protobuf:"bytes,2,opt,name=field2,proto3" json:"field2,omitempty"`
unknownFields protoimpl.UnknownFields
sizeCache protoimpl.SizeCache
}
func (x *VideoMsgExtra) Reset() {
*x = VideoMsgExtra{}
mi := &file_proto_wxproto_video_msg_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
func (x *VideoMsgExtra) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*VideoMsgExtra) ProtoMessage() {}
func (x *VideoMsgExtra) ProtoReflect() protoreflect.Message {
mi := &file_proto_wxproto_video_msg_proto_msgTypes[2]
if x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
ms.StoreMessageInfo(mi)
}
return ms
}
return mi.MessageOf(x)
}
// Deprecated: Use VideoMsgExtra.ProtoReflect.Descriptor instead.
func (*VideoMsgExtra) Descriptor() ([]byte, []int) {
return file_proto_wxproto_video_msg_proto_rawDescGZIP(), []int{2}
}
func (x *VideoMsgExtra) GetField1() int32 {
if x != nil {
return x.Field1
}
return 0
}
func (x *VideoMsgExtra) GetField2() []byte {
if x != nil {
return x.Field2
}
return nil
}
var File_proto_wxproto_video_msg_proto protoreflect.FileDescriptor
const file_proto_wxproto_video_msg_proto_rawDesc = "" +
"\n" +
"\x1dproto/wxproto/video_msg.proto\x12\awxproto\"\x9c\a\n" +
"\x0eWxSendVideoMsg\x12/\n" +
"\x06header\x18\x01 \x01(\v2\x17.wxproto.VideoMsgHeaderR\x06header\x12\"\n" +
"\rclient_msg_id\x18\x02 \x01(\fR\vclientMsgId\x12\x16\n" +
"\x06sender\x18\x03 \x01(\fR\x06sender\x12\x1a\n" +
"\breceiver\x18\x04 \x01(\fR\breceiver\x12\x1a\n" +
"\bunknown5\x18\x05 \x01(\x05R\bunknown5\x12\x1a\n" +
"\bunknown6\x18\x06 \x01(\x05R\bunknown6\x122\n" +
"\bunknown7\x18\a \x01(\v2\x16.wxproto.VideoMsgExtraR\bunknown7\x12\x1a\n" +
"\bunknown8\x18\b \x01(\x05R\bunknown8\x12\x1a\n" +
"\bunknown9\x18\t \x01(\x05R\bunknown9\x124\n" +
"\tunknown10\x18\n" +
" \x01(\v2\x16.wxproto.VideoMsgExtraR\tunknown10\x12\x1a\n" +
"\bduration\x18\v \x01(\x05R\bduration\x12\x1c\n" +
"\tunknown12\x18\f \x01(\x05R\tunknown12\x12\x1c\n" +
"\tunknown13\x18\r \x01(\x05R\tunknown13\x12\x1c\n" +
"\tunknown14\x18\x0e \x01(\x05R\tunknown14\x12\x10\n" +
"\x03xml\x18\x0f \x01(\fR\x03xml\x12\x17\n" +
"\acdn_key\x18\x10 \x01(\fR\x06cdnKey\x12\x17\n" +
"\aaes_key\x18\x11 \x01(\fR\x06aesKey\x12\x1c\n" +
"\tunknown18\x18\x12 \x01(\x05R\tunknown18\x12\x19\n" +
"\bcdn_key2\x18\x13 \x01(\fR\acdnKey2\x12\x1c\n" +
"\tunknown20\x18\x14 \x01(\x05R\tunknown20\x12\x1c\n" +
"\tunknown21\x18\x15 \x01(\x05R\tunknown21\x12\x1c\n" +
"\tunknown22\x18\x16 \x01(\x05R\tunknown22\x12\x19\n" +
"\baes_key2\x18\x17 \x01(\fR\aaesKey2\x12\x17\n" +
"\amd5_key\x18\x1a \x01(\fR\x06md5Key\x12\x19\n" +
"\bvideo_id\x18% \x01(\fR\avideoId\x12\x1c\n" +
"\tunknown38\x18& \x01(\x05R\tunknown38\x12\x19\n" +
"\bmd5_key2\x180 \x01(\fR\amd5Key2\x12\x19\n" +
"\bcdn_key3\x181 \x01(\fR\acdnKey3\x12\x19\n" +
"\baes_key3\x182 \x01(\fR\aaesKey3\x12\x1c\n" +
"\tunknown51\x183 \x01(\x05R\tunknown51\"\xb1\x01\n" +
"\x0eVideoMsgHeader\x12\x12\n" +
"\x04flag\x18\x01 \x01(\fR\x04flag\x12\x15\n" +
"\x06msg_id\x18\x02 \x01(\x03R\x05msgId\x12!\n" +
"\fclient_proof\x18\x03 \x01(\fR\vclientProof\x12\x1a\n" +
"\bunknown4\x18\x04 \x01(\x03R\bunknown4\x12\x19\n" +
"\bsys_info\x18\x05 \x01(\fR\asysInfo\x12\x1a\n" +
"\bunknown6\x18\x06 \x01(\x05R\bunknown6\"?\n" +
"\rVideoMsgExtra\x12\x16\n" +
"\x06field1\x18\x01 \x01(\x05R\x06field1\x12\x16\n" +
"\x06field2\x18\x02 \x01(\fR\x06field2B>Z<github.com/yincongcyincong/weixin-macos/onebot/proto/wxprotob\x06proto3"
var (
file_proto_wxproto_video_msg_proto_rawDescOnce sync.Once
file_proto_wxproto_video_msg_proto_rawDescData []byte
)
func file_proto_wxproto_video_msg_proto_rawDescGZIP() []byte {
file_proto_wxproto_video_msg_proto_rawDescOnce.Do(func() {
file_proto_wxproto_video_msg_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_proto_wxproto_video_msg_proto_rawDesc), len(file_proto_wxproto_video_msg_proto_rawDesc)))
})
return file_proto_wxproto_video_msg_proto_rawDescData
}
var file_proto_wxproto_video_msg_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
var file_proto_wxproto_video_msg_proto_goTypes = []any{
(*WxSendVideoMsg)(nil), // 0: wxproto.WxSendVideoMsg
(*VideoMsgHeader)(nil), // 1: wxproto.VideoMsgHeader
(*VideoMsgExtra)(nil), // 2: wxproto.VideoMsgExtra
}
var file_proto_wxproto_video_msg_proto_depIdxs = []int32{
1, // 0: wxproto.WxSendVideoMsg.header:type_name -> wxproto.VideoMsgHeader
2, // 1: wxproto.WxSendVideoMsg.unknown7:type_name -> wxproto.VideoMsgExtra
2, // 2: wxproto.WxSendVideoMsg.unknown10:type_name -> wxproto.VideoMsgExtra
3, // [3:3] is the sub-list for method output_type
3, // [3:3] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_proto_wxproto_video_msg_proto_init() }
func file_proto_wxproto_video_msg_proto_init() {
if File_proto_wxproto_video_msg_proto != nil {
return
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: unsafe.Slice(unsafe.StringData(file_proto_wxproto_video_msg_proto_rawDesc), len(file_proto_wxproto_video_msg_proto_rawDesc)),
NumEnums: 0,
NumMessages: 3,
NumExtensions: 0,
NumServices: 0,
},
GoTypes: file_proto_wxproto_video_msg_proto_goTypes,
DependencyIndexes: file_proto_wxproto_video_msg_proto_depIdxs,
MessageInfos: file_proto_wxproto_video_msg_proto_msgTypes,
}.Build()
File_proto_wxproto_video_msg_proto = out.File
file_proto_wxproto_video_msg_proto_goTypes = nil
file_proto_wxproto_video_msg_proto_depIdxs = nil
}
+56
View File
@@ -0,0 +1,56 @@
syntax = "proto3";
package wxproto;
option go_package = "github.com/yincongcyincong/weixin-macos/onebot/proto/wxproto";
// 发送视频消息的protobuf结构
message WxSendVideoMsg {
VideoMsgHeader header = 1;
bytes client_msg_id = 2;
bytes sender = 3;
bytes receiver = 4;
int32 unknown5 = 5;
int32 unknown6 = 6;
VideoMsgExtra unknown7 = 7;
int32 unknown8 = 8;
int32 unknown9 = 9;
VideoMsgExtra unknown10 = 10;
int32 duration = 11;
int32 unknown12 = 12;
int32 unknown13 = 13;
int32 unknown14 = 14;
bytes xml = 15;
bytes cdn_key = 16;
bytes aes_key = 17;
int32 unknown18 = 18;
bytes cdn_key2 = 19;
int32 unknown20 = 20;
int32 unknown21 = 21;
int32 unknown22 = 22;
bytes aes_key2 = 23;
// fields 24-25 skipped
bytes md5_key = 26;
// fields 27-36 skipped
bytes video_id = 37;
int32 unknown38 = 38;
// fields 39-47 skipped
bytes md5_key2 = 48;
bytes cdn_key3 = 49;
bytes aes_key3 = 50;
int32 unknown51 = 51;
}
message VideoMsgHeader {
bytes flag = 1;
int64 msg_id = 2;
bytes client_proof = 3;
int64 unknown4 = 4;
bytes sys_info = 5;
int32 unknown6 = 6;
}
message VideoMsgExtra {
int32 field1 = 1;
bytes field2 = 2;
}
+18 -280
View File
@@ -14,63 +14,6 @@ function hexToByteArray(hexStr) {
return bytes;
}
function toVarint(n) {
let res = [];
while (n >= 128) {
res.push((n & 0x7F) | 0x80); // 取后7位,最高位置1
n = n >> 7; // 右移7位
}
res.push(n); // 最后一位最高位为0
return res;
}
function stringToHexArray(str) {
var utf8Str = unescape(encodeURIComponent(str));
var arr = [];
for (var i = 0; i < utf8Str.length; i++) {
arr.push(utf8Str.charCodeAt(i)); // 获取字符的 ASCII 码 (即十六进制值)
}
return arr;
}
function generateRandom5ByteVarint() {
let res = [];
// 前 4 个字节:最高位(bit 7)必须是 1,低 7 位随机
for (let i = 0; i < 4; i++) {
let random7Bit = Math.floor(Math.random() * 128);
res.push(random7Bit | 0x80); // 强制设置最高位为 1
}
// 第 5 个字节:最高位必须是 0,为了确保不变成 4 字节,低 7 位不能全为 0
let lastByte = Math.floor(Math.random() * 127) + 1;
res.push(lastByte & 0x7F); // 确保最高位为 0
return res;
}
// 辅助函数:Protobuf Varint 编码 (对应 get_varint_timestamp_bytes)
function getVarintTimestampBytes() {
let ts = Math.floor(Date.now() / 1000);
let encodedBytes = [];
let tempTs = ts >>> 0; // 强制转为 32位 无符号整数
while (true) {
let byte = tempTs & 0x7F;
tempTs >>>= 7;
if (tempTs !== 0) {
encodedBytes.push(byte | 0x80);
} else {
encodedBytes.push(byte);
break;
}
}
return encodedBytes;
}
function patchString(addr, plainStr) {
const bytes = [];
for (let i = 0; i < plainStr.length; i++) {
@@ -90,19 +33,6 @@ function generateAESKey() {
return key;
}
function generateBytes(n) {
// 生成随机字符串
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
let result = '';
for (let i = 0; i < n; i++) {
result += chars.charAt(Math.floor(Math.random() * chars.length));
}
return stringToHexArray(result);
}
// -------------------------基础函数分区-------------------------
// -------------------------全局变量分区-------------------------
@@ -206,18 +136,12 @@ var senderGlobal = "wxid_"
var lastSendTime = 0;
var atUserGlobal = "";
// 图片/视频发送cdn信息全局变量 (从Go直接传入)
var imgCdnKeyGlobal = "";
var imgAesKeyGlobal = "";
var imgMd5KeyGlobal = "";
var videoCdnKeyGlobal = "";
var videoAesKeyGlobal = "";
var videoMd5KeyGlobal = "";
var videoIdGlobal = "";
// 文本消息protobuf全局变量 (从Go直接传入hex编码)
var textProtoHexGlobal = "";
const fileCp = generateBytes(16)
// 图片消息protobuf全局变量 (从Go直接传入hex编码)
var imgProtoHexGlobal = "";
// 视频消息protobuf全局变量 (从Go直接传入hex编码)
var videoProtoHexGlobal = "";
// -------------------------全局变量分区-------------------------
@@ -532,7 +456,7 @@ function setupSendImgMessageDynamic() {
uploadAesKeyAddr = Memory.alloc(256);
ImagePathAddr1 = Memory.alloc(256);
uploadImageX1 = Memory.alloc(1024);
imgProtoX1PayloadAddr = Memory.alloc(1024);
imgProtoX1PayloadAddr = Memory.alloc(2048);
// 图片数据写入
patchString(imgCgiAddr, "/cgi-bin/micromsg-bin/uploadmsgimg");
@@ -688,7 +612,7 @@ function patchVideoProtoBuf() {
setImmediate(patchVideoProtoBuf);
function triggerSendImgMessage(taskId, sender, receiver, cdnKey, aesKey, md5Key) {
function triggerSendImgMessage(taskId, sender, receiver, protoHex) {
if (!taskId || !receiver || !sender) {
console.error("[!] taskId or receiver or sender is empty!");
return "fail";
@@ -699,10 +623,8 @@ function triggerSendImgMessage(taskId, sender, receiver, cdnKey, aesKey, md5Key)
return "fail";
}
// 保存cdn信息供attachProto使用
imgCdnKeyGlobal = cdnKey;
imgAesKeyGlobal = aesKey;
imgMd5KeyGlobal = md5Key;
// 保存protobuf hex供attachProto使用
imgProtoHexGlobal = protoHex;
// 获取当前时间戳 (秒)
const timestamp = Math.floor(Date.now() / 1000);
@@ -787,7 +709,7 @@ function triggerSendImgMessage(taskId, sender, receiver, cdnKey, aesKey, md5Key)
}
}
function triggerSendVideoMessage(taskId, sender, receiver, cdnKey, aesKey, md5Key, videoId) {
function triggerSendVideoMessage(taskId, sender, receiver, protoHex) {
if (!taskId || !receiver || !sender) {
console.error("[!] taskId or receiver or sender is empty!");
return "fail";
@@ -798,11 +720,8 @@ function triggerSendVideoMessage(taskId, sender, receiver, cdnKey, aesKey, md5Ke
return "fail";
}
// 保存cdn信息供attachProto使用
videoCdnKeyGlobal = cdnKey;
videoAesKeyGlobal = aesKey;
videoMd5KeyGlobal = md5Key;
videoIdGlobal = videoId;
// 保存protobuf hex供attachProto使用
videoProtoHexGlobal = protoHex;
// 获取当前时间戳 (秒)
const timestamp = Math.floor(Date.now() / 1000);
@@ -898,104 +817,16 @@ function attachProto() {
return;
}
// 使用从Go传入的全局cdn信息
let cdnKey = imgCdnKeyGlobal;
let aesKey = imgAesKeyGlobal;
let md5Key = imgMd5KeyGlobal;
let targetId = receiverGlobal;
if (!cdnKey || !aesKey || !md5Key) {
console.error("[!] 无法获取图片上传信息")
return
if (!imgProtoHexGlobal || imgProtoHexGlobal.length === 0) {
console.error("[!] imgProtoHexGlobal 为空");
return;
}
const type = [0x0A, 0x40, 0x0A, 0x01, 0x00]
const msgId = [0x10].concat(generateRandom5ByteVarint())
const cpHeader = [0x1A, 0x10]
const randomId = [0x20, 0xAF, 0xAC, 0x90, 0x93, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01]
const sysHeader = [0x2A, 0x15]
// UnifiedPCMac 26 arm64
const sys = [0x55, 0x6E, 0x69, 0x66, 0x69, 0x65, 0x64, 0x50, 0x43, 0x4D, 0x61, 0x63, 0x20, 0x32, 0x36, 0x20, 0x61, 0x72, 0x6D, 0x36, 0x34, 0x30]
// 45872025384@chatroom_176787000_60_xwechat_1 只需要改这个时间戳就能重复发送
const receiverMsgId = stringToHexArray(targetId).concat([0x5F])
.concat(stringToHexArray(Math.floor(Date.now() / 1000).toString()))
.concat([0x5F, 0x31, 0x36, 0x30, 0x5F, 0x78, 0x77, 0x65, 0x63, 0x68, 0x61, 0x74, 0x5F, 0x33]);
// 0xb0, 0x02 是长度,需要看一下什么的长度
const msgIdHeader = [0xb0, 0x02, 0x12, receiverMsgId.length + 2, 0x0A, receiverMsgId.length]
const senderHeader = [0x1A, senderGlobal.length + 2, 0x0A, senderGlobal.length];
// wxid_xxxx 或者 chatroom
const sender = stringToHexArray(senderGlobal);
const receiverHeader = [0x22, targetId.length + 2, 0x0A, targetId.length]
// wxid_xxxx
const receiver = stringToHexArray(targetId)
const randomId1 = [0x28, 0xF4, 0x0B]
const type1 = [0x30, 0x00]
const randomId2 = [0x38, 0xF4, 0x0B]
const randomId3 = [0x42, 0x04, 0x08, 0x00, 0x12, 0x00]
const randomId4 = [0x48, 0x03]
const htmlHeader = [0x52, 0x32];
const html = [0x3C,
0x6D, 0x73, 0x67, 0x73, 0x6F, 0x75, 0x72, // 0x30 msgsour
0x63, 0x65, 0x3E, 0x3C, 0x61, 0x6C, 0x6E, 0x6F, // 0x38 ce><alno
0x64, 0x65, 0x3E, 0x3C, 0x66, 0x72, 0x3E, 0x31, // 0x40 de><fr>1
0x3C, 0x2F, 0x66, 0x72, 0x3E, 0x3C, 0x2F, 0x61, // 0x48 </fr></a
0x6C, 0x6E, 0x6F, 0x64, 0x65, 0x3E, 0x3C, 0x2F, // 0x50 lnode></
0x6D, 0x73, 0x67, 0x73, 0x6F, 0x75, 0x72, // 0x58 msgsour
0x63, 0x65, 0x3E // 0x60 ce>
];
const cdnHeader = [0x58, 0x01, 0x60, 0x02, 0x68, 0x00, 0x7A, 0xB2, 0x01]
// 3057 开头的cdn key
const cdn = stringToHexArray(cdnKey);
const cdn2Header = [0x82, 0x01, 0xB2, 0x01]
const cdn2 = stringToHexArray(cdnKey)
const aesKeyHeader = [0x8A, 0x01, 0x20]
const aesKeyBytes = stringToHexArray(aesKey)
const randomId5 = [0x90, 0x01, 0x01, 0x98, 0x01, 0xFF, // 0x2C8
0x13, 0xA0, 0x01, 0xFF, 0x13]
const cdn3Header = [0xAA, 0x01, 0xB2, 0x01]
const cdn3 = stringToHexArray(cdnKey)
const randomId6 = [0xB0, 0x01, 0xF4, 0x0B]
const randomId7 = [0xB8, 0x01, 0x68]
const randomId8 = [0xC0, 0x01, 0x3A]
const aesKey1Header = [0xCA, 0x01, 0x20]
const aesKey1 = stringToHexArray(aesKey)
const md5Header = [0xDA, 0x01, 0x20]
const me5Key = stringToHexArray(md5Key)
const randomId9 = [0xE0, 0x01, 0xd9, 0xe7, 0xc7, 0xF3, 0x02]
var left0 = [
0xF0, 0x01, 0x00, 0xA0, 0x02, 0x00, // 0x3E0
0xC8, 0x02, 0x00, 0x00 // 0x3E8
]
const finalPayload = type.concat(msgId, cpHeader, fileCp, randomId, sysHeader, sys, msgIdHeader, receiverMsgId,
senderHeader, sender, receiverHeader, receiver, randomId1, type1, randomId2, randomId3, randomId4, htmlHeader, html,
cdnHeader, cdn, cdn2Header, cdn2, aesKeyHeader, aesKeyBytes, randomId5, cdn3Header, cdn3, randomId6, randomId7, randomId8,
aesKey1Header, aesKey1, md5Header, me5Key, randomId9, left0)
const finalPayload = hexToByteArray(imgProtoHexGlobal);
imgProtoX1PayloadAddr.writeByteArray(finalPayload);
this.context.x1 = imgProtoX1PayloadAddr;
this.context.x2 = ptr(finalPayload.length);
// console.log("[+] 图片 寄存器修改完成: X1=" + this.context.x1 + ", X2=" + this.context.x2, hexdump(imgProtoX1PayloadAddr, {
// offset: 0,
// length: 256,
// header: true,
// ansi: true
// }));
},
});
@@ -1007,109 +838,16 @@ function attachProto() {
return;
}
// 使用从Go传入的全局cdn信息
let cdnKey = videoCdnKeyGlobal;
let aesKey = videoAesKeyGlobal;
let md5Key = videoMd5KeyGlobal;
let videoId = videoIdGlobal;
let targetId = receiverGlobal;
if (!cdnKey || !aesKey || !md5Key) {
console.error("[!] 无法获取视频上传信息");
if (!videoProtoHexGlobal || videoProtoHexGlobal.length === 0) {
console.error("[!] videoProtoHexGlobal 为空");
return;
}
const type = [0x0A, 0x3f, 0x0A, 0x01, 0x00]
const msgId = [0x10].concat(generateRandom5ByteVarint())
const cpHeader = [0x1A, 0x10]
const randomId = [0x20, 0xAF, 0xAC, 0x90, 0x93, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x01]
const sysHeader = [0x2A, 0x15]
// UnifiedPCMac 26 arm64
const sys = [0x55, 0x6E, 0x69, 0x66, 0x69, 0x65, 0x64, 0x50, 0x43, 0x4D, 0x61, 0x63, 0x20, 0x32, 0x36, 0x20, 0x61, 0x72, 0x6D, 0x36, 0x34]
// 注意:这里 sender 和 receiver 互换了
const receiverMsgId = stringToHexArray(targetId).concat([0x5F])
.concat(stringToHexArray(Math.floor(Date.now() / 1000).toString()))
.concat([0x5F, 0x31, 0x36, 0x30, 0x5F, 0x78, 0x77, 0x65, 0x63, 0x68, 0x61, 0x74, 0x5F, 0x31]);
// 0x81, 0x01 是 tag0x12, 0x2b 是长度=43
const msgIdHeader = [0x30, 0x76, 0x12, receiverMsgId.length]
const senderHeader = [0x1A, senderGlobal.length];
// sender 和 receiver 互换了,sender 是 wxid_ldftuhe36izg19
const sender = stringToHexArray(senderGlobal);
const receiverHeader = [0x22, targetId.length]
// receiver 是 wxid_7wd1ece99f7i21
const receiver = stringToHexArray(targetId)
const randomId1 = [0x28, 0xac, 0x73, 0x30, 0xac, 0x73, 0x3a, 0x04, 0x08, 0x00, 0x12, 0x00]
const type1 = [0x40, 0xe8, 0xf2, 0x6f]
const randomId2 = [0x48, 0xe8, 0xf2, 0x6f]
const randomId3 = [0x52, 0x04, 0x08, 0x00, 0x12, 0x00]
const randomId4 = [0x58, 0x0d, 0x60, 0x01, 0x68, 0x02, 0x70, 0x00]
const htmlHeader = [0x7a, 0x3c];
const html = [0x3C, 0x6D, 0x73, 0x67, 0x73, 0x6F, 0x75, 0x72, 0x63, 0x65,
0x3E, 0x3C, 0x61, 0x6C, 0x6E, 0x6F, 0x64, 0x65, 0x3E, 0x3C, 0x66, 0x72,
0x3E, 0x31, 0x3C, 0x2F, 0x66, 0x72, 0x3E, 0x3C, 0x63, 0x66, 0x3E, 0x33,
0x3C, 0x2F, 0x63, 0x66, 0x3E, 0x3C, 0x2F, 0x61, 0x6C, 0x6E, 0x6F, 0x64,
0x65, 0x3E, 0x3C, 0x2F, 0x6D, 0x73, 0x67, 0x73, 0x6F, 0x75, 0x72, 0x63,
0x65, 0x3E]
const cdnHeader = [0x82, 0x01, ...toVarint(cdnKey.length)]
// 3057 开头的cdn key
const cdn = stringToHexArray(cdnKey);
const aesKeyHeader = [0x8A, 0x01, 0x20]
const aesKeyBytes = stringToHexArray(aesKey)
const randomId5 = [0x90, 0x01, 0x01, 0x9A, 0x01, ...toVarint(cdnKey.length)]
const cdn2 = stringToHexArray(cdnKey)
const randomId6 = [0xA0, 0x01, 0xAC, 0x73, 0xA8, 0x01, 0xE8, 0x02, 0xB0, 0x01, 0xCB, 0x01]
const aesKey1Header = [0xBA, 0x01, 0x20]
const aesKey1 = stringToHexArray(aesKey)
const md5Header = [0xd2, 0x01, 0x20]
const md5KeyBytes = stringToHexArray(md5Key)
const md5Header1 = [0xAA, 0x02, 0x20]
const md5Key1 = stringToHexArray(videoId)
const randomId7 = [0xB0, 0x02, 0x00]
const md5Key2Header = [0x82, 0x03, 0x20]
const md5Key2 = stringToHexArray(md5Key)
const cdn3Header = [0x8A, 0x03, ...toVarint(cdnKey.length)]
const cdn3 = stringToHexArray(cdnKey)
const randomId8 = [0x92, 0x03, 0x20]
const md5Key3 = stringToHexArray(aesKey)
var left0 = [
0x98, 0x03, 0xe8, 0xf2, 0x6f
]
const finalPayload = type.concat(msgId, cpHeader, fileCp, randomId, sysHeader, sys, msgIdHeader, receiverMsgId,
senderHeader, sender, receiverHeader, receiver, randomId1, type1, randomId2, randomId3, randomId4, htmlHeader, html,
cdnHeader, cdn, aesKeyHeader, aesKeyBytes, randomId5, cdn2, randomId6, aesKey1Header, aesKey1, md5Header, md5KeyBytes, md5Header1,
md5Key1, randomId7, md5Key2Header, md5Key2, cdn3Header, cdn3, randomId8, md5Key3, left0)
const finalPayload = hexToByteArray(videoProtoHexGlobal);
videoProtoX1PayloadAddr.writeByteArray(finalPayload);
this.context.x1 = videoProtoX1PayloadAddr;
this.context.x2 = ptr(finalPayload.length);
// console.log("[+] 视频寄存器修改完成: X1=" + this.context.x1 + ", X2=" + this.context.x2, hexdump(videoProtoX1PayloadAddr, {
// offset: 0,
// length: finalPayload.length,
// header: true,
// ansi: true
// }));
},
});
}
+23
View File
@@ -61,6 +61,29 @@ func SaveBase64Image(base64Data string) (string, string, error) {
return targetPath, md5Str, nil
}
// GetVideoDuration 使用ffprobe获取视频时长(秒)
func GetVideoDuration(filePath string) (int32, error) {
cmd := exec.Command("ffprobe",
"-v", "error",
"-show_entries", "format=duration",
"-of", "default=noprint_wrappers=1:nokey=1",
filePath,
)
var out bytes.Buffer
cmd.Stdout = &out
if err := cmd.Run(); err != nil {
return 0, fmt.Errorf("ffprobe error: %v", err)
}
durationStr := strings.TrimSpace(out.String())
durationFloat, err := strconv.ParseFloat(durationStr, 64)
if err != nil {
return 0, fmt.Errorf("parse duration failed: %v", err)
}
return int32(durationFloat), nil
}
func GetFileMD5(filePath string) (string, error) {
file, err := os.Open(filePath)
if err != nil {
+97
View File
@@ -0,0 +1,97 @@
package main
import (
"crypto/rand"
"encoding/hex"
"fmt"
mathrand "math/rand"
"strconv"
"time"
"github.com/yincongcyincong/weixin-macos/onebot/proto/wxproto"
"google.golang.org/protobuf/proto"
)
// BuildVideoMsgProto 构建发送视频消息的protobuf并返回hex编码的字符串
func BuildVideoMsgProto(sender, targetId, cdnKey, aesKey, md5Key, videoId string, duration int32) (string, error) {
// 生成16字节随机client_proof
clientProof := make([]byte, 16)
const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
randBytes := make([]byte, 16)
rand.Read(randBytes)
for i := range clientProof {
clientProof[i] = chars[int(randBytes[i])%len(chars)]
}
// 生成5字节varint范围的msgId (2^28 ~ 2^35-1)
msgId := mathrand.Int63n(1<<35-1<<28) + (1 << 28)
// header.unknown4: 同图片proto
const headerUnknown4 int64 = -228321745
// client_msg_id: targetId_timestamp_160_xwechat_1
timestamp := time.Now().Unix()
clientMsgId := targetId + "_" + strconv.FormatInt(timestamp, 10) + "_160_xwechat_1"
// xml内容 (视频多了<cf>3</cf>)
xmlContent := []byte("<msgsource><alnode><fr>1</fr><cf>3</cf></alnode></msgsource>")
msg := &wxproto.WxSendVideoMsg{
Header: &wxproto.VideoMsgHeader{
Flag: []byte{0x00},
MsgId: msgId,
ClientProof: clientProof,
Unknown4: headerUnknown4,
SysInfo: []byte("UnifiedPCMac 26 arm64"),
Unknown6: 118,
},
ClientMsgId: []byte(clientMsgId),
Sender: []byte(sender),
Receiver: []byte(targetId),
Unknown5: 14764,
Unknown6: 14764,
Unknown7: &wxproto.VideoMsgExtra{
Field1: 0,
Field2: []byte{},
},
Unknown8: 1833320,
Unknown9: 1833320,
Unknown10: &wxproto.VideoMsgExtra{
Field1: 0,
Field2: []byte{},
},
Duration: duration,
Unknown12: 1,
Unknown13: 2,
// Unknown14: 0, // 需要手动追加
Xml: xmlContent,
CdnKey: []byte(cdnKey),
AesKey: []byte(aesKey),
Unknown18: 1,
CdnKey2: []byte(cdnKey),
Unknown20: 14764,
Unknown21: 360,
Unknown22: 203,
AesKey2: []byte(aesKey),
Md5Key: []byte(md5Key),
VideoId: []byte(videoId),
// Unknown38: 0, // 需要手动追加
Md5Key2: []byte(md5Key),
CdnKey3: []byte(cdnKey),
AesKey3: []byte(aesKey),
Unknown51: 1833320,
}
data, err := proto.Marshal(msg)
if err != nil {
return "", fmt.Errorf("marshal video proto failed: %w", err)
}
// 手动追加proto3不会序列化的0值字段
// field 14 (unknown14=0)
data = appendZeroVarintField(data, 14)
// field 38 (unknown38=0)
data = appendZeroVarintField(data, 38)
return hex.EncodeToString(data), nil
}
+28 -6
View File
@@ -78,7 +78,12 @@ func SendWechatMsg(m *SendMsg) {
return
}
case "send_image":
result := fridaScript.ExportsCall("triggerSendImgMessage", currTaskId, myWechatId, targetId, m.CdnKey, m.AesKey, m.Md5Key)
protoHex, err := BuildImgMsgProto(myWechatId, targetId, m.CdnKey, m.AesKey, m.Md5Key)
if err != nil {
Error("构建图片protobuf失败", "err", err)
return
}
result := fridaScript.ExportsCall("triggerSendImgMessage", currTaskId, myWechatId, targetId, protoHex)
Info("📩 发送图片任务执行结果", "result", result, "task_id", currTaskId, "wechat_id", myWechatId, "target_id", targetId)
if result != "1" {
Error("上传图片失败", "task_id", currTaskId, "target_id", targetId, "result", result)
@@ -90,18 +95,35 @@ func SendWechatMsg(m *SendMsg) {
Error("保存图片失败", "err", err)
return
}
// 获取视频时长
duration, err := GetVideoDuration(targetPath)
if err != nil {
Error("获取视频时长失败", "err", err)
} else {
videoDurationMap.Store(targetId, duration)
}
result := fridaScript.ExportsCall("triggerUploadVideo", targetId, md5Str, targetPath)
Info("📩 上传视频任务执行结果", "result", result, "target_id", targetId, "md5", md5Str, "path", targetPath)
Info("📩 上传视频任务执行结果", "result", result, "target_id", targetId, "md5", md5Str, "path", targetPath, "duration", duration)
if result != "0" {
Error("上传视频失败", "target_id", targetId, "md5", md5Str, "result", result)
return
}
case "send_video":
result := fridaScript.ExportsCall("triggerSendVideoMessage", currTaskId, myWechatId, targetId, m.CdnKey, m.AesKey, m.Md5Key, m.VideoId)
Info("📩 发送视频任务执行结果", "result", result, "task_id", currTaskId, "wechat_id", myWechatId, "target_id", targetId)
var duration int32
if d, ok := videoDurationMap.LoadAndDelete(targetId); ok {
duration = d.(int32)
}
protoHex, err := BuildVideoMsgProto(myWechatId, targetId, m.CdnKey, m.AesKey, m.Md5Key, m.VideoId, duration)
if err != nil {
Error("构建视频protobuf失败", "err", err)
return
}
result := fridaScript.ExportsCall("triggerSendVideoMessage", currTaskId, myWechatId, targetId, protoHex)
Info("📩 发送视频任务执行结果", "result", result, "task_id", currTaskId, "wechat_id", myWechatId, "target_id", targetId, "duration", duration)
if result != "1" {
Error("上传图片失败", "task_id", currTaskId, "target_id", targetId, "result", result)
Error("发送视频失败", "task_id", currTaskId, "target_id", targetId, "result", result)
return
}
case "download":