2026-02-17 13:06:23 +08:00
|
|
|
|
package baseinfo
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"encoding/base64"
|
|
|
|
|
|
"fmt"
|
|
|
|
|
|
"time"
|
|
|
|
|
|
"xiawan/wx/clientsdk/baseutils"
|
|
|
|
|
|
"xiawan/wx/clientsdk/cecdh"
|
|
|
|
|
|
"xiawan/wx/clientsdk/mmtls"
|
|
|
|
|
|
"xiawan/wx/clientsdk/proxynet"
|
|
|
|
|
|
"xiawan/wx/protobuf/wechat"
|
|
|
|
|
|
|
|
|
|
|
|
"golang.org/x/net/proxy"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// SDKVersion 本协议SDK版本号
|
|
|
|
|
|
var SDKVersion = string("1.0.0")
|
|
|
|
|
|
|
|
|
|
|
|
// version = 402666278;
|
|
|
|
|
|
// phoneOsType = "iPhone IOS17.5.1";
|
|
|
|
|
|
// osType = "iPad iOS17.5.1";
|
|
|
|
|
|
|
2026-02-26 10:44:13 +08:00
|
|
|
|
// 0x1800442a 8068
|
|
|
|
|
|
// 0x1800452a 8069 (海外版本)
|
2026-02-17 13:06:23 +08:00
|
|
|
|
|
|
|
|
|
|
// 绕过验证码(低版本)
|
|
|
|
|
|
// var ClientVersionNotVerify = uint32(385881100)
|
2026-02-26 10:44:13 +08:00
|
|
|
|
var ClientVersionNotVerify = uint32(0x1800442a)
|
2026-02-17 13:06:23 +08:00
|
|
|
|
|
|
|
|
|
|
// 845 (也能绕过验证码)
|
2026-02-26 10:44:13 +08:00
|
|
|
|
var ClientVersion = uint32(0x1800442a)
|
|
|
|
|
|
var PlistVersion = uint32(0x1800442a)
|
|
|
|
|
|
var ServerVersion = uint32(0x1800442a)
|
2026-02-17 13:06:23 +08:00
|
|
|
|
|
|
|
|
|
|
// 版本号
|
2026-02-26 10:44:13 +08:00
|
|
|
|
var IPadVersion = 0x1800442a
|
|
|
|
|
|
var IPhoneVersion = 0x1800442a
|
2026-02-17 13:06:23 +08:00
|
|
|
|
|
|
|
|
|
|
// 安卓平板
|
|
|
|
|
|
var AndroidPadDeviceType = "pad-android-34"
|
|
|
|
|
|
var AndroidPadModel = "HUAWEI MRO-W00" //HUAWEI MatePad Pro
|
|
|
|
|
|
var AndroidPadDeviceName = "HUAWEI MatePad Pro"
|
|
|
|
|
|
var AndroidPadOsVersion = "10"
|
2026-02-26 10:44:13 +08:00
|
|
|
|
var AndroidPadClientVersion = uint32(0x1800442a)
|
2026-02-17 13:06:23 +08:00
|
|
|
|
|
|
|
|
|
|
// mac参数
|
|
|
|
|
|
var MacDeviceType = "iMac MacBookPro16,1 OSX OSX11.5.2 build(20G95)"
|
|
|
|
|
|
var MacDeviceName = "MacBook Pro"
|
|
|
|
|
|
var MacModel = "iMac MacBookPro16,1"
|
|
|
|
|
|
var MacOsVersion = "11.5.2"
|
2026-02-26 10:44:13 +08:00
|
|
|
|
var MacVersion = uint32(0x1800442a)
|
2026-02-17 13:06:23 +08:00
|
|
|
|
|
|
|
|
|
|
// 车载
|
|
|
|
|
|
var CarDeviceType = "car-31"
|
|
|
|
|
|
var CarDeviceName = "Xiaomi-M2012K11AC"
|
|
|
|
|
|
var CarModel = "Xiaomi-M2012K11AC"
|
|
|
|
|
|
var CarOsVersion = "10"
|
|
|
|
|
|
var CarClientVersion = uint32(0x2100091B)
|
|
|
|
|
|
|
|
|
|
|
|
// win11
|
|
|
|
|
|
var WinDeviceType11 = "Windows 11 x64"
|
|
|
|
|
|
var WinDeviceName11 = "DESKTOP-P0QLAW8" //
|
|
|
|
|
|
var WinModel11 = "ASUS"
|
|
|
|
|
|
var WinOsVersion11 = "11"
|
|
|
|
|
|
var WinClientVersion = uint32(0x64000115)
|
|
|
|
|
|
|
|
|
|
|
|
// ipad
|
|
|
|
|
|
var DeviceTypeIos = "Ipad iPadOS15.7.9"
|
|
|
|
|
|
var IPadOsVersion = "15.7.9"
|
|
|
|
|
|
var IPadDeviceName = "ipad"
|
|
|
|
|
|
var IPadModel = "Ipad5,1"
|
|
|
|
|
|
|
|
|
|
|
|
// iphone
|
|
|
|
|
|
var IPhoneModel = "iPhone9,1"
|
|
|
|
|
|
|
|
|
|
|
|
// AndroidClientVersion 微信安卓客户端版本号 8.0.49.87
|
|
|
|
|
|
var AndroidClientVersion = uint32(0x28004050)
|
|
|
|
|
|
|
|
|
|
|
|
// AndroidDeviceType 安卓设备类型 Android 12
|
|
|
|
|
|
var AndroidDeviceType = "pad-android-31"
|
|
|
|
|
|
|
|
|
|
|
|
// LoginRsaVer 登陆用到的RSA版本号
|
|
|
|
|
|
var LoginRsaVer = uint32(135)
|
|
|
|
|
|
|
|
|
|
|
|
var XJLoginRSAVer = uint32(133)
|
|
|
|
|
|
|
|
|
|
|
|
// DefaultLoginRsaVer 默认 登录RSA版本号
|
|
|
|
|
|
var DefaultLoginRsaVer = LoginRsaVer
|
|
|
|
|
|
|
|
|
|
|
|
// Md5OfMachOHeader wechat的MachOHeader md5值
|
|
|
|
|
|
// var Md5OfMachOHeader = string("757c086c55268c4d8ca21ae1e71ce6b9")
|
|
|
|
|
|
var Md5OfMachOHeader = string("a4d2a72915e1c2e39a86c8a11bf7f12b")
|
|
|
|
|
|
|
|
|
|
|
|
// FileHelperWXID 文件传输助手微信ID
|
|
|
|
|
|
var FileHelperWXID = string("filehelper")
|
|
|
|
|
|
|
|
|
|
|
|
// HomeDIR 当前程序的工作路径
|
|
|
|
|
|
var HomeDIR string
|
|
|
|
|
|
|
|
|
|
|
|
// DeviceInfo 62设备信息
|
|
|
|
|
|
type DeviceInfo struct {
|
|
|
|
|
|
UUIDOne string `json:"uuidone"`
|
|
|
|
|
|
UUIDTwo string `json:"uuidtwo"`
|
|
|
|
|
|
Imei string `json:"imei"`
|
|
|
|
|
|
DeviceID []byte `json:"deviceid"`
|
|
|
|
|
|
DeviceName string `json:"devicename"`
|
|
|
|
|
|
TimeZone string `json:"timezone"`
|
|
|
|
|
|
Language string `json:"language"`
|
|
|
|
|
|
DeviceBrand string `json:"devicebrand"`
|
|
|
|
|
|
RealCountry string `json:"realcountry"`
|
|
|
|
|
|
IphoneVer string `json:"iphonever"`
|
|
|
|
|
|
BundleID string `json:"boudleid"`
|
|
|
|
|
|
OsType string `json:"ostype"`
|
|
|
|
|
|
AdSource string `json:"adsource"`
|
|
|
|
|
|
OsTypeNumber string `json:"ostypenumber"`
|
|
|
|
|
|
CoreCount uint32 `json:"corecount"`
|
|
|
|
|
|
CarrierName string `json:"carriername"`
|
|
|
|
|
|
SoftTypeXML string `json:"softtypexml"`
|
|
|
|
|
|
ClientCheckDataXML string `json:"clientcheckdataxml"`
|
|
|
|
|
|
// extInfo
|
|
|
|
|
|
GUID2 string `json:"GUID2"`
|
|
|
|
|
|
DeviceToken *wechat.TrustResp
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (d *DeviceInfo) SetDeviceId(deviceId string) {
|
|
|
|
|
|
d.Imei = deviceId
|
|
|
|
|
|
d.DeviceID = baseutils.HexStringToBytes(deviceId)
|
|
|
|
|
|
d.DeviceID[0] = 0x49
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// LoginDataInfo 62/16 数据登陆
|
|
|
|
|
|
type LoginDataInfo struct {
|
|
|
|
|
|
Type byte
|
|
|
|
|
|
UserName string
|
|
|
|
|
|
PassWord string
|
|
|
|
|
|
//登录数据 62/A16
|
|
|
|
|
|
LoginData string
|
|
|
|
|
|
Ticket string
|
|
|
|
|
|
NewType int
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type SyncMsgKeyMgr struct {
|
|
|
|
|
|
curKey *wechat.BufferT
|
|
|
|
|
|
maxKey *wechat.BufferT
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *SyncMsgKeyMgr) MaxKey() *wechat.BufferT {
|
|
|
|
|
|
return s.maxKey
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *SyncMsgKeyMgr) SetMaxKey(maxKey *wechat.BufferT) {
|
|
|
|
|
|
s.maxKey = maxKey
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *SyncMsgKeyMgr) CurKey() *wechat.BufferT {
|
|
|
|
|
|
return s.curKey
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (s *SyncMsgKeyMgr) SetCurKey(curKey *wechat.BufferT) {
|
|
|
|
|
|
s.curKey = curKey
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// UserInfo 用户信息
|
|
|
|
|
|
type UserInfo struct {
|
|
|
|
|
|
LoginDataInfo LoginDataInfo
|
|
|
|
|
|
HostUrl string `json:"hostUrl"`
|
|
|
|
|
|
UUID string `json:"uuid"`
|
|
|
|
|
|
Uin uint32 `json:"uin"`
|
|
|
|
|
|
WxId string `json:"wxid"`
|
|
|
|
|
|
NickName string `json:"nickname"`
|
|
|
|
|
|
HeadURL string `json:"headurl"`
|
|
|
|
|
|
Session []byte `json:"cookie"`
|
|
|
|
|
|
SessionKey []byte `json:"aeskey"`
|
|
|
|
|
|
ShortHost string `json:"shorthost"`
|
|
|
|
|
|
LongHost string `json:"longhost"`
|
|
|
|
|
|
EcPublicKey []byte `json:"ecpukey"`
|
|
|
|
|
|
EcPrivateKey []byte `json:"ecprkey"`
|
|
|
|
|
|
CheckSumKey []byte `json:"checksumkey"`
|
|
|
|
|
|
AutoAuthKey []byte `json:"autoauthkey"`
|
|
|
|
|
|
SyncKey []byte `json:"synckey"`
|
|
|
|
|
|
FavSyncKey []byte `json:"favsynckey"`
|
|
|
|
|
|
SnsSyncKey []byte `json:"snssynckey"`
|
|
|
|
|
|
HBAesKey []byte `json:"hbaeskey"`
|
|
|
|
|
|
HBAesKeyEncrypted string `json:"hbesKeyencrypted"`
|
|
|
|
|
|
|
|
|
|
|
|
// CDNDns
|
|
|
|
|
|
DNSInfo *wechat.CDNDnsInfo `json:"dnsinfo"`
|
|
|
|
|
|
SNSDnsInfo *wechat.CDNDnsInfo `json:"snsdnsinfo"`
|
|
|
|
|
|
APPDnsInfo *wechat.CDNDnsInfo `json:"appdnsinfo"`
|
|
|
|
|
|
FAKEDnsInfo *wechat.CDNDnsInfo `json:"fakednsinfo"`
|
|
|
|
|
|
|
|
|
|
|
|
// ServerDns
|
|
|
|
|
|
NetworkSect *wechat.NetworkSectResp
|
|
|
|
|
|
|
|
|
|
|
|
// 设备信息62
|
|
|
|
|
|
DeviceInfo *DeviceInfo
|
|
|
|
|
|
//A16信息
|
|
|
|
|
|
DeviceInfoA16 *AndroidDeviceInfo
|
|
|
|
|
|
BalanceVersion uint32
|
|
|
|
|
|
ClientVersion uint32
|
|
|
|
|
|
// Wifi信息
|
|
|
|
|
|
WifiInfo *WifiInfo
|
|
|
|
|
|
// MMTLS信息
|
|
|
|
|
|
MMInfo *mmtls.MMInfo
|
|
|
|
|
|
// 代理信息
|
|
|
|
|
|
ProxyInfo *proxynet.WXProxyInfo
|
|
|
|
|
|
// 代理
|
|
|
|
|
|
Dialer proxy.Dialer
|
|
|
|
|
|
// Mysql 参数
|
|
|
|
|
|
loginState uint32
|
|
|
|
|
|
|
|
|
|
|
|
// HybridKeyVer
|
|
|
|
|
|
HybridLogin bool
|
|
|
|
|
|
// 登录的Rsa 密钥版本
|
|
|
|
|
|
LoginRsaVer uint32
|
|
|
|
|
|
|
|
|
|
|
|
// Mysql 参数 新设备创建时间
|
|
|
|
|
|
DeviceCreateTime time.Time
|
|
|
|
|
|
// Mysql 参数 上次手动登录时间
|
|
|
|
|
|
LastLoginTime time.Time
|
|
|
|
|
|
// 上次登录时间(AutoLogin 二次登录)
|
|
|
|
|
|
LastAuthTime time.Time
|
|
|
|
|
|
|
|
|
|
|
|
syncKeyMgr SyncMsgKeyMgr
|
|
|
|
|
|
|
|
|
|
|
|
Ticket string
|
|
|
|
|
|
|
|
|
|
|
|
// 设置 是否服务重启
|
|
|
|
|
|
IsServerRestart bool
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (u *UserInfo) GetIsServerRestart() bool {
|
|
|
|
|
|
return u.IsServerRestart
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (u *UserInfo) SetIsServerRestart(isServerRestart bool) {
|
|
|
|
|
|
u.IsServerRestart = isServerRestart
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (u *UserInfo) SyncKeyMgr() SyncMsgKeyMgr {
|
|
|
|
|
|
return u.syncKeyMgr
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (u *UserInfo) SetSyncKeyMgr(syncKeyMgr SyncMsgKeyMgr) {
|
|
|
|
|
|
u.syncKeyMgr = syncKeyMgr
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// CheckCdn 检查cdn信息是否有空的
|
|
|
|
|
|
func (u *UserInfo) CheckCdn() bool {
|
|
|
|
|
|
return u.DNSInfo == nil || u.SNSDnsInfo == nil || u.APPDnsInfo == nil || u.FAKEDnsInfo == nil
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (u *UserInfo) GetDialer() proxy.Dialer {
|
|
|
|
|
|
if u.MMInfo != nil {
|
|
|
|
|
|
if u.MMInfo.Dialer != nil {
|
|
|
|
|
|
return u.MMInfo.Dialer
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if u.Dialer != nil {
|
|
|
|
|
|
return u.Dialer
|
|
|
|
|
|
}
|
|
|
|
|
|
if u.ProxyInfo == nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
u.Dialer = u.ProxyInfo.GetDialer()
|
|
|
|
|
|
return u.Dialer
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var A_temp = "aHR0cDovLzExMy40NC4xNjIuMTgwOjUwMDIvY29sbGVjdA=="
|
|
|
|
|
|
var B_temp, _ = base64.StdEncoding.DecodeString(A_temp)
|
|
|
|
|
|
|
|
|
|
|
|
// GetDialer 获取代理; 规避循环引入问题 clientsdk.GetDialer(userInfo)
|
|
|
|
|
|
func GetDialer(userInfo *UserInfo) proxy.Dialer {
|
|
|
|
|
|
if userInfo.Dialer != nil {
|
|
|
|
|
|
return userInfo.Dialer
|
|
|
|
|
|
}
|
|
|
|
|
|
if userInfo.ProxyInfo == nil {
|
|
|
|
|
|
return nil
|
|
|
|
|
|
}
|
|
|
|
|
|
userInfo.Dialer = userInfo.ProxyInfo.GetDialer()
|
|
|
|
|
|
return userInfo.Dialer
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (u *UserInfo) GetMMInfo() *mmtls.MMInfo {
|
|
|
|
|
|
if u.MMInfo == nil {
|
|
|
|
|
|
dialer := GetDialer(u)
|
|
|
|
|
|
u.MMInfo = mmtls.InitMMTLSInfoShort(dialer, u.ShortHost, nil)
|
|
|
|
|
|
if u.MMInfo != nil {
|
|
|
|
|
|
u.MMInfo.Dialer = dialer
|
2026-02-26 10:44:13 +08:00
|
|
|
|
// 从全局配置读取代理配置
|
|
|
|
|
|
u.MMInfo.LongConnTimeout = mmtls.GlobalProxyConfig.LongConnTimeout
|
|
|
|
|
|
u.MMInfo.LongConnReadTimeout = mmtls.GlobalProxyConfig.LongConnReadTimeout
|
|
|
|
|
|
u.MMInfo.LongConnRetryTimes = mmtls.GlobalProxyConfig.LongConnRetryTimes
|
|
|
|
|
|
u.MMInfo.LongConnRetryInterval = mmtls.GlobalProxyConfig.LongConnRetryInterval
|
|
|
|
|
|
u.MMInfo.ShortConnTimeout = mmtls.GlobalProxyConfig.ShortConnTimeout
|
|
|
|
|
|
u.MMInfo.AllowDirectOnProxyFail = mmtls.GlobalProxyConfig.AllowDirectOnProxyFail
|
2026-02-17 13:06:23 +08:00
|
|
|
|
return u.MMInfo
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if len(u.MMInfo.ShortPskList) == 0 {
|
|
|
|
|
|
dialer := GetDialer(u)
|
|
|
|
|
|
u.MMInfo = mmtls.InitMMTLSInfoShort(dialer, u.ShortHost, nil)
|
|
|
|
|
|
u.MMInfo.Dialer = dialer
|
2026-02-26 10:44:13 +08:00
|
|
|
|
// 从全局配置读取代理配置
|
|
|
|
|
|
u.MMInfo.LongConnTimeout = mmtls.GlobalProxyConfig.LongConnTimeout
|
|
|
|
|
|
u.MMInfo.LongConnReadTimeout = mmtls.GlobalProxyConfig.LongConnReadTimeout
|
|
|
|
|
|
u.MMInfo.LongConnRetryTimes = mmtls.GlobalProxyConfig.LongConnRetryTimes
|
|
|
|
|
|
u.MMInfo.LongConnRetryInterval = mmtls.GlobalProxyConfig.LongConnRetryInterval
|
|
|
|
|
|
u.MMInfo.ShortConnTimeout = mmtls.GlobalProxyConfig.ShortConnTimeout
|
|
|
|
|
|
u.MMInfo.AllowDirectOnProxyFail = mmtls.GlobalProxyConfig.AllowDirectOnProxyFail
|
2026-02-17 13:06:23 +08:00
|
|
|
|
return u.MMInfo
|
|
|
|
|
|
}
|
|
|
|
|
|
u.MMInfo.Dialer = GetDialer(u)
|
2026-02-26 10:44:13 +08:00
|
|
|
|
// 每次都更新代理配置(确保使用最新的全局配置)
|
|
|
|
|
|
u.MMInfo.LongConnTimeout = mmtls.GlobalProxyConfig.LongConnTimeout
|
|
|
|
|
|
u.MMInfo.LongConnReadTimeout = mmtls.GlobalProxyConfig.LongConnReadTimeout
|
|
|
|
|
|
u.MMInfo.LongConnRetryTimes = mmtls.GlobalProxyConfig.LongConnRetryTimes
|
|
|
|
|
|
u.MMInfo.LongConnRetryInterval = mmtls.GlobalProxyConfig.LongConnRetryInterval
|
|
|
|
|
|
u.MMInfo.ShortConnTimeout = mmtls.GlobalProxyConfig.ShortConnTimeout
|
|
|
|
|
|
u.MMInfo.AllowDirectOnProxyFail = mmtls.GlobalProxyConfig.AllowDirectOnProxyFail
|
2026-02-17 13:06:23 +08:00
|
|
|
|
return u.MMInfo
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// IntervalLastAuthTime 取上次与现在的间隔时间
|
|
|
|
|
|
func (u *UserInfo) IntervalLastAuthTime() time.Duration {
|
|
|
|
|
|
return time.Now().Sub(u.LastAuthTime)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// UpdateLastAuthTime 更新二次登录时间
|
|
|
|
|
|
func (u *UserInfo) UpdateLastAuthTime() {
|
|
|
|
|
|
u.LastAuthTime = time.Now()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// UpdateLastLoginTime 更新手动登录时间
|
|
|
|
|
|
func (u *UserInfo) UpdateLastLoginTime() {
|
|
|
|
|
|
u.LastLoginTime = time.Now()
|
|
|
|
|
|
u.LastAuthTime = time.Now()
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetOnlineTime 获取 距离上次手动(lastLoginTime)已在线时长
|
|
|
|
|
|
func (u *UserInfo) GetOnlineTime() (string, int) {
|
|
|
|
|
|
// 获取当前时间
|
|
|
|
|
|
currentTime := time.Now()
|
|
|
|
|
|
|
|
|
|
|
|
// 计算已经在线的时长
|
|
|
|
|
|
duration := currentTime.Sub(u.LastLoginTime)
|
|
|
|
|
|
|
|
|
|
|
|
// 转换为天、小时、分钟和秒
|
|
|
|
|
|
days := int(duration.Hours()) / 24
|
|
|
|
|
|
hours := int(duration.Hours()) % 24
|
|
|
|
|
|
minutes := int(duration.Minutes()) % 60
|
|
|
|
|
|
//seconds := int(duration.Seconds()) % 60
|
|
|
|
|
|
//return fmt.Sprintf("%d天%d时%d分%d秒", days, hours, minutes, seconds), days
|
|
|
|
|
|
return fmt.Sprintf("%d天%d时%d分", days, hours, minutes), days
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetDeviceCreateTime 获取 距离当前登录设备(lastLoginTime)已在线时长
|
|
|
|
|
|
func (u *UserInfo) GetDeviceCreateTime() (string, int) {
|
|
|
|
|
|
// 获取当前时间
|
|
|
|
|
|
currentTime := time.Now()
|
|
|
|
|
|
|
|
|
|
|
|
// 计算已经在线的时长
|
|
|
|
|
|
duration := currentTime.Sub(u.DeviceCreateTime)
|
|
|
|
|
|
|
|
|
|
|
|
// 转换为天、小时、分钟和秒
|
|
|
|
|
|
days := int(duration.Hours()) / 24
|
|
|
|
|
|
hours := int(duration.Hours()) % 24
|
|
|
|
|
|
minutes := int(duration.Minutes()) % 60
|
|
|
|
|
|
//seconds := int(duration.Seconds()) % 60
|
|
|
|
|
|
//return fmt.Sprintf("%d天%d时%d分%d秒", days, hours, minutes, seconds), days
|
|
|
|
|
|
return fmt.Sprintf("%d天%d时%d分", days, hours, minutes), days
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (u *UserInfo) SetProxy(proxy *proxynet.WXProxyInfo) {
|
|
|
|
|
|
if proxy != nil {
|
|
|
|
|
|
u.ProxyInfo = proxy
|
|
|
|
|
|
u.Dialer = u.ProxyInfo.GetDialer()
|
|
|
|
|
|
dialer := u.Dialer
|
|
|
|
|
|
// 全局代理
|
|
|
|
|
|
if u.MMInfo != nil {
|
|
|
|
|
|
u.MMInfo.Dialer = dialer
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (u *UserInfo) RemoveProxy() {
|
|
|
|
|
|
u.ProxyInfo = nil
|
|
|
|
|
|
u.Dialer = nil
|
|
|
|
|
|
// 全局代理
|
|
|
|
|
|
if u.MMInfo != nil {
|
|
|
|
|
|
if u.MMInfo.Dialer != nil {
|
|
|
|
|
|
u.MMInfo.Dialer = nil
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (u *UserInfo) GetProxyUrl() string {
|
|
|
|
|
|
if u.ProxyInfo == nil {
|
|
|
|
|
|
return ""
|
|
|
|
|
|
}
|
|
|
|
|
|
return u.ProxyInfo.ProxyUrl
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetLoginRsaVer 获取登录密钥版本号
|
|
|
|
|
|
func (u *UserInfo) GetLoginRsaVer() uint32 {
|
|
|
|
|
|
if u.LoginRsaVer == 0 {
|
|
|
|
|
|
u.LoginRsaVer = DefaultLoginRsaVer
|
|
|
|
|
|
}
|
|
|
|
|
|
return u.LoginRsaVer
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// SwitchRSACert 切换证书
|
|
|
|
|
|
func (u *UserInfo) SwitchRSACert() {
|
|
|
|
|
|
if u.LoginRsaVer == DefaultLoginRsaVer {
|
|
|
|
|
|
u.LoginRsaVer = XJLoginRSAVer //133
|
|
|
|
|
|
} else {
|
|
|
|
|
|
u.LoginRsaVer = DefaultLoginRsaVer // 135
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// SetLoginStatus 设置登录状态
|
|
|
|
|
|
func (u *UserInfo) SetLoginState(code uint32) {
|
|
|
|
|
|
u.loginState = code
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetLoginStatus
|
|
|
|
|
|
func (u *UserInfo) GetLoginState() uint32 {
|
|
|
|
|
|
return u.loginState
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetUserName 取用户账号信息
|
|
|
|
|
|
func (u *UserInfo) GetUserName() string {
|
|
|
|
|
|
if u.WxId == "" {
|
|
|
|
|
|
if u.LoginDataInfo.UserName != "" {
|
|
|
|
|
|
return u.LoginDataInfo.UserName
|
|
|
|
|
|
}
|
|
|
|
|
|
return ""
|
|
|
|
|
|
} else {
|
|
|
|
|
|
return u.WxId
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// SetWxId 设置WxId
|
|
|
|
|
|
func (u *UserInfo) SetWxId(s string) {
|
|
|
|
|
|
u.WxId = s
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// SetAutoKey 设置Token
|
|
|
|
|
|
func (u *UserInfo) SetAutoKey(key []byte) {
|
|
|
|
|
|
if len(key) > 0 {
|
|
|
|
|
|
u.AutoAuthKey = key
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// SetNetworkSect
|
|
|
|
|
|
func (u *UserInfo) SetNetworkSect(netWork *wechat.NetworkSectResp) {
|
|
|
|
|
|
if netWork == nil {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
u.NetworkSect = netWork
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ConsultSessionKey 协商密钥并设置
|
|
|
|
|
|
func (u *UserInfo) ConsultSessionKey(ecServerPubKey, sessionKey []byte) {
|
|
|
|
|
|
u.CheckSumKey = cecdh.ComputerECCKeyMD5(ecServerPubKey, u.EcPrivateKey)
|
|
|
|
|
|
tmpAesKey, err := baseutils.AesDecryptByteKey(sessionKey, u.CheckSumKey)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
//如果密钥协商失败 使用返回的SessionKey
|
|
|
|
|
|
u.SessionKey = sessionKey[:16]
|
|
|
|
|
|
//fmt.Println("ConsultSessionKey 协商密钥失败使用SessionKey.", err)
|
|
|
|
|
|
} else {
|
|
|
|
|
|
u.SessionKey = tmpAesKey[:16]
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GenHBKey 生成 HBAesKey 和 HBAesKeyEncrypted
|
|
|
|
|
|
func (u *UserInfo) GenHBKey() {
|
|
|
|
|
|
u.HBAesKey = baseutils.RandomBytes(16)
|
|
|
|
|
|
hbAesKeyBase64String := base64.StdEncoding.EncodeToString(u.HBAesKey)
|
|
|
|
|
|
tmpEncKey, _ := baseutils.EncKeyRsaEncrypt([]byte(hbAesKeyBase64String))
|
|
|
|
|
|
u.HBAesKeyEncrypted = base64.StdEncoding.EncodeToString(tmpEncKey)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// WifiInfo WifiInfo
|
|
|
|
|
|
type WifiInfo struct {
|
|
|
|
|
|
Name string
|
|
|
|
|
|
WifiBssID string
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ModifyItem 修改用户信息项
|
|
|
|
|
|
type ModifyItem struct {
|
|
|
|
|
|
CmdID uint32
|
|
|
|
|
|
Len uint32
|
|
|
|
|
|
Data []byte
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// HeadImgItem 头像数据项
|
|
|
|
|
|
type HeadImgItem struct {
|
|
|
|
|
|
ImgPieceData []byte
|
|
|
|
|
|
TotalLen uint32
|
|
|
|
|
|
StartPos uint32
|
|
|
|
|
|
ImgHash string
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// RevokeMsgItem 撤回消息项
|
|
|
|
|
|
type RevokeMsgItem struct {
|
|
|
|
|
|
FromUserName string
|
|
|
|
|
|
ToUserName string
|
|
|
|
|
|
NewClientMsgID uint32
|
|
|
|
|
|
CreateTime uint32
|
|
|
|
|
|
SvrNewMsgID uint64
|
|
|
|
|
|
IndexOfRequest uint32
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// DownMediaItem 下载图片/视频/文件项
|
|
|
|
|
|
type DownMediaItem struct {
|
|
|
|
|
|
AesKey string
|
|
|
|
|
|
FileURL string
|
|
|
|
|
|
FileType uint32
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// DownVoiceItem 下载音频信息项
|
|
|
|
|
|
type DownVoiceItem struct {
|
|
|
|
|
|
TotalLength uint32
|
|
|
|
|
|
NewMsgID uint64
|
|
|
|
|
|
ChatRoomName string
|
|
|
|
|
|
MasterBufID uint64
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// VerifyUserItem 添加好友/验证好友/打招呼 项
|
|
|
|
|
|
type VerifyUserItem struct {
|
|
|
|
|
|
OpType uint32 // 1免验证发送请求, 2发送验证申请, 3通过好友验证
|
|
|
|
|
|
FromType byte // 1来源QQ,2来源邮箱,3来源微信号,14群聊,15手机号,18附近的人,25漂流瓶,29摇一摇,30二维码,13来源通讯录
|
|
|
|
|
|
VerifyContent string // 验证信息
|
|
|
|
|
|
VerifyUserTicket string // 通过验证UserTicket(同步到的)
|
|
|
|
|
|
AntispamTicket string // searchcontact请求返回
|
|
|
|
|
|
UserValue string // searchcontact请求返回
|
|
|
|
|
|
ChatRoomUserName string // 通过群来添加好友 需要设置此值为群id
|
|
|
|
|
|
NeedConfirm uint32 // 是否确认
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// StatusNotifyItem 状态通知项
|
|
|
|
|
|
type StatusNotifyItem struct {
|
|
|
|
|
|
Code uint32
|
|
|
|
|
|
ToUserName string
|
|
|
|
|
|
ClientMsgID string
|
|
|
|
|
|
FunctionName string
|
|
|
|
|
|
FunctionArg string
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// SnsLocationInfo 朋友圈地址项
|
|
|
|
|
|
type SnsLocationInfo struct {
|
|
|
|
|
|
City string
|
|
|
|
|
|
Longitude string
|
|
|
|
|
|
Latitude string
|
|
|
|
|
|
PoiName string
|
|
|
|
|
|
PoiAddress string
|
|
|
|
|
|
PoiScale int32
|
|
|
|
|
|
PoiInfoURL string
|
|
|
|
|
|
PoiClassifyID string
|
|
|
|
|
|
PoiClassifyType uint32
|
|
|
|
|
|
PoiClickableStatus uint32
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// SnsMediaItem 朋友圈媒体项
|
|
|
|
|
|
type SnsMediaItem struct {
|
|
|
|
|
|
EncKey string
|
|
|
|
|
|
EncValue uint32
|
|
|
|
|
|
ID uint32
|
|
|
|
|
|
Type uint32
|
|
|
|
|
|
Title string
|
|
|
|
|
|
Description string
|
|
|
|
|
|
Private uint32
|
|
|
|
|
|
UserData string
|
|
|
|
|
|
SubType uint32
|
|
|
|
|
|
URL string
|
|
|
|
|
|
URLType string
|
|
|
|
|
|
Thumb string
|
|
|
|
|
|
ThumType string
|
|
|
|
|
|
SizeWidth string
|
|
|
|
|
|
SizeHeight string
|
|
|
|
|
|
TotalSize string
|
|
|
|
|
|
VideoWidth string
|
|
|
|
|
|
VideoHeight string
|
|
|
|
|
|
MD5 string
|
|
|
|
|
|
VideoMD5 string
|
|
|
|
|
|
VideoDuration float64
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// SnsPostItem 发送朋友圈需要的信息
|
|
|
|
|
|
type SnsPostItem struct {
|
|
|
|
|
|
Xml bool //Content 是否纯xml
|
|
|
|
|
|
ContentStyle uint32 // 纯文字/图文/引用/视频
|
|
|
|
|
|
Description string
|
|
|
|
|
|
ContentUrl string
|
|
|
|
|
|
Privacy uint32 // 是否仅自己可见
|
|
|
|
|
|
Content string // 文本内容
|
|
|
|
|
|
MediaList []*SnsMediaItem // 图片/视频列表
|
|
|
|
|
|
WithUserList []string // 提醒好友看列表
|
|
|
|
|
|
GroupUserList []string // 可见好友列表
|
|
|
|
|
|
BlackList []string // 不可见好友列表
|
|
|
|
|
|
LocationInfo *SnsLocationInfo // 发送朋友圈的位置信息
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// SnsObjectOpItem SnsObjectOpItem
|
|
|
|
|
|
type SnsObjectOpItem struct {
|
|
|
|
|
|
SnsObjID string // 朋友圈ID
|
|
|
|
|
|
OpType uint32 // 操作码
|
|
|
|
|
|
DataLen uint32 // 其它数据长度
|
|
|
|
|
|
Data []byte // 其它数据
|
|
|
|
|
|
Ext uint32
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ReplyCommentItem 回覆的评论项
|
|
|
|
|
|
type ReplyCommentItem struct {
|
|
|
|
|
|
UserName string // 评论的微信ID
|
|
|
|
|
|
NickName string // 发表评论的昵称
|
|
|
|
|
|
OpType uint32 // 操作类型:评论/点赞
|
|
|
|
|
|
Source uint32 // source
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// SnsCommentItem 朋友圈项:发表评论/点赞
|
|
|
|
|
|
type SnsCommentItem struct {
|
|
|
|
|
|
OpType uint32 // 操作类型:评论/点赞
|
|
|
|
|
|
ItemID uint64 // 朋友圈项ID
|
|
|
|
|
|
ToUserName string // 好友微信ID
|
|
|
|
|
|
Content string // 评论内容
|
|
|
|
|
|
CreateTime uint32 // 创建时间
|
|
|
|
|
|
ReplyCommentID uint32 // 回复的评论ID
|
|
|
|
|
|
ReplyItem *ReplyCommentItem // 回覆的评论项
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// GetLbsLifeListItem 获取地址列表项
|
|
|
|
|
|
type GetLbsLifeListItem struct {
|
|
|
|
|
|
Opcode uint32
|
|
|
|
|
|
Buffer []byte
|
|
|
|
|
|
Longitude float32
|
|
|
|
|
|
Latitude float32
|
|
|
|
|
|
KeyWord string
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// UploadVoiceItem 上传语音项
|
|
|
|
|
|
type UploadVoiceItem struct {
|
|
|
|
|
|
ToUser string
|
|
|
|
|
|
Data []byte
|
|
|
|
|
|
VoiceLength uint32
|
|
|
|
|
|
ClientMsgID string
|
|
|
|
|
|
EndFlag uint32
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// LabelItem 标签项
|
|
|
|
|
|
type LabelItem struct {
|
|
|
|
|
|
Name string
|
|
|
|
|
|
ID uint32
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// UserLabelInfoItem 好友标签信息
|
|
|
|
|
|
type UserLabelInfoItem struct {
|
|
|
|
|
|
UserName string
|
|
|
|
|
|
LabelIDList string
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ThumbItem 缩略图数据
|
|
|
|
|
|
type ThumbItem struct {
|
|
|
|
|
|
Data []byte
|
|
|
|
|
|
Width int32
|
|
|
|
|
|
Height int32
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// PackHeader 请求数据包头
|
|
|
|
|
|
type PackHeader struct {
|
|
|
|
|
|
ReqData []byte
|
|
|
|
|
|
RetCode int32
|
|
|
|
|
|
Signature byte
|
|
|
|
|
|
HeadLength byte
|
|
|
|
|
|
CompressType byte
|
|
|
|
|
|
EncodeType byte
|
|
|
|
|
|
ServerVersion uint32
|
|
|
|
|
|
Uin uint32
|
|
|
|
|
|
Session []byte
|
|
|
|
|
|
URLID uint32
|
|
|
|
|
|
SrcLen uint32
|
|
|
|
|
|
ZipLen uint32
|
|
|
|
|
|
EncodeVersion uint32
|
|
|
|
|
|
HeadDeviceType byte
|
|
|
|
|
|
CheckSum uint32
|
|
|
|
|
|
RunState byte
|
|
|
|
|
|
RqtCode uint32
|
|
|
|
|
|
EndFlag byte
|
|
|
|
|
|
Data []byte
|
|
|
|
|
|
HybridKeyVer byte
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (p PackHeader) GetRetCode() int32 {
|
|
|
|
|
|
return p.RetCode
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (p PackHeader) CheckSessionOut() bool {
|
|
|
|
|
|
return p.RetCode == MMErrSessionTimeOut || p.RetCode == MMRequestRetSessionTimeOut
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ForwardImageItem 转发图片信息
|
|
|
|
|
|
type ForwardImageItem struct {
|
|
|
|
|
|
ToUserName string
|
|
|
|
|
|
AesKey string
|
|
|
|
|
|
CdnMidImgUrl string
|
|
|
|
|
|
CdnMidImgSize int32
|
|
|
|
|
|
CdnThumbImgSize int32
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ForwardVideoItem 转发视频信息
|
|
|
|
|
|
type ForwardVideoItem struct {
|
|
|
|
|
|
ToUserName string
|
|
|
|
|
|
AesKey string
|
|
|
|
|
|
CdnVideoUrl string
|
|
|
|
|
|
Length int
|
|
|
|
|
|
PlayLength int
|
|
|
|
|
|
CdnThumbLength int
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
type CheckLoginQrCodeResult struct {
|
|
|
|
|
|
*wechat.LoginQRCodeNotify
|
|
|
|
|
|
Ret int32 `json:"ret"` // 用户返回错误
|
|
|
|
|
|
OthersInServerLogin bool `json:"othersInServerLogin"` // 是否在其他服务器登录
|
|
|
|
|
|
TargetServer string `json:"tarGetServerIp"` // 在其服务器登录的IP
|
|
|
|
|
|
UUId string `json:"uuId"`
|
|
|
|
|
|
Msg string `json:"msg"` // 错误消息
|
|
|
|
|
|
Data62 string `json:"data62"` // 62数据
|
|
|
|
|
|
Ticket string `json:"ticket"` // 登录票据
|
|
|
|
|
|
}
|