package app import ( "context" "encoding/base64" "encoding/hex" "encoding/json" "errors" "fmt" waProto "git.bobomao.top/joey/testwh/binary/proto" "github.com/gogf/gf/util/gconv" "github.com/golang/protobuf/proto" "github.com/ulule/deepcopier" "log" ) // IsEmpty func IsEmpty(s string) bool { return s == "" || len(s) <= 0 } type AuthDataDto struct { *ClientPayload } type AuthDataDtoActual struct { *waProto.ClientPayload } // LoginDto 登录信息 type LoginDto struct { // socks 5 代理 UUID string Socks5 string AuthBody *AuthDataDto AuthBodyActual *AuthDataDtoActual // AuthHexData 握手认证数据 AuthHexData string // StaticPriKey 认证私钥 StaticPriKey string // StaticPubKey 认证公钥 StaticPubKey string //注册返回 ClientStaticKeypair string //EdgeRouting EdgeRouting string // IdentityPubKey string IdentityPriKey string Hash string } func (loginDto *LoginDto) Init() { loginDto.AuthBodyActual = &AuthDataDtoActual{ ClientPayload: &waProto.ClientPayload{ UserAgent: &waProto.ClientPayload_UserAgent{ AppVersion: &waProto.ClientPayload_UserAgent_AppVersion{}, }, }, } //playload := loginDto.AuthBodyActual.ClientPayload //playloadActual := loginDto.AuthBodyActual.ClientPayload playload := loginDto.AuthBody.ClientPayload playloadActual := loginDto.AuthBodyActual.ClientPayload deepcopier.Copy(playload).To(playloadActual) deepcopier.Copy(playload.UserAgent).To(playloadActual.UserAgent) deepcopier.Copy(playload.UserAgent.AppVersion).To(playloadActual.UserAgent.AppVersion) playloadActual.UserAgent.Platform = (*waProto.ClientPayload_UserAgent_Platform)(playload.UserAgent.Platform) //playload } type DHKey struct { Private []byte Public []byte } var DHString = []byte{69, 68, 0, 1} var InitString = []byte("WA") type VerifyCallbackFunc func(publicKey []byte, data []byte) error // WAProtocolVersion noise 握手版本 type WAProtocolVersion struct { // 主要版本 VersionMajor byte // 次要版本 VersionMinor byte } type WAHandshakeSettings struct { RoutingInfo []byte //认证数据 Payload []byte //certificates, signs etc // 用户注册时生成的公私秘钥 StaticKey DHKey // 服务器公钥 PeerStatic []byte } // loginInfo type loginInfo struct { ctx context.Context // login info clientPayload *waProto.ClientPayload priKey, pubKey []byte routingInfo []byte staticPubKey *[32]byte staticPriKey *[32]byte } func (l *loginInfo) GetStaticPubKey() *[32]byte { return l.staticPubKey } func (l *loginInfo) SetStaticPubKey(d string) error { data, err := base64.StdEncoding.DecodeString(d) if err != nil { return err } if len(data) == 33 { data = data[1:] } var byteArray [32]byte copy(byteArray[:], data) l.staticPubKey = &byteArray return nil } func (l *loginInfo) GetStaticPriKey() *[32]byte { return l.staticPriKey } func (l *loginInfo) SetStaticPriKey(d string) error { data, err := base64.StdEncoding.DecodeString(d) if err != nil { return err } if len(data) == 33 { data = data[1:] } var byteArray [32]byte copy(byteArray[:], data) l.staticPriKey = &byteArray return nil } func (l *loginInfo) Ctx() context.Context { return l.ctx } func (l *loginInfo) SetRoutingInfo(d []byte) { l.routingInfo = d } func (l *loginInfo) SetStaticHdBase64Keys(pri, pub string) error { priData, err := base64.StdEncoding.DecodeString(pri) if err != nil { return err } pubData, err := base64.StdEncoding.DecodeString(pub) if err != nil { return err } if len(priData) != 32 || len(pubData) < 32 { return errors.New("keys length less than 32 bit") } if len(pubData) == 33 { pubData = pubData[1:] } if len(priData) == 33 { priData = priData[1:] } // set keys l.priKey, l.pubKey = priData, pubData return nil } func (l *loginInfo) SetStaticHdKeys(pri, pub []byte) error { if len(pri) != 32 || len(pub) != 32 { return errors.New("keys length less than 32 bit") } // set keys l.priKey, l.pubKey = pri, pub return nil } // SetStaticKeys func (l *loginInfo) SetStaticKeys(base64Data string) error { skData, err := base64.StdEncoding.DecodeString(base64Data) if err != nil { return err } // if sk data length not 64 if len(skData) < 64 { return errors.New("static keys length less than 64 bit") } // set static keys l.priKey, l.pubKey = skData[:32], skData[32:] return nil } func (l *loginInfo) SetCliPayload(payload *waProto.ClientPayload) { if payload != nil { l.clientPayload = payload } } // SetCliPayloadData func (l *loginInfo) SetCliPayloadData(data []byte) error { return proto.Unmarshal(data, l.clientPayload) } // GetLoginSettings func (l *loginInfo) GetLoginSettings() *WAHandshakeSettings { return &WAHandshakeSettings{ RoutingInfo: l.routingInfo, Payload: l.buildClientPayload(), StaticKey: DHKey{ Private: l.priKey, Public: l.pubKey, }, PeerStatic: []byte{}, } } func (l *loginInfo) buildClientPayload() []byte { if l.clientPayload == nil { return nil } d, _ := json.MarshalIndent(&l.clientPayload, " ", " ") log.Println("AUTHDATA:", string(d)) //db.PushQueue( // db.PushMsg{ // Time: time.Now().Unix(), // UserName: l.clientPayload.GetUsername(), // Type: db.System.Number(), // Data: l.clientPayload, // }, //) // marshal payloadData, err := proto.Marshal(l.clientPayload) if err != nil { return nil } log.Println("payloadData", hex.EncodeToString(payloadData)) return payloadData } // AccountInfo type AccountInfo struct { *loginInfo verifiedName uint64 } func EmptyAccountInfo() *AccountInfo { return &AccountInfo{ loginInfo: &loginInfo{ ctx: context.Background(), clientPayload: &waProto.ClientPayload{}, priKey: []byte{}, pubKey: []byte{}, routingInfo: []byte{}, }} } // GetUserName func (a *AccountInfo) GetUserName() string { if a.clientPayload != nil { return gconv.String(a.clientPayload.GetUsername()) } return "" } func (a *AccountInfo) GetVeriFiledName() uint64 { if a.verifiedName != 0 { return a.verifiedName } return 0 } func (a *AccountInfo) SetVeriFiledName(VeriFiledName uint64) { a.verifiedName = VeriFiledName } // 获取平台 func (a *AccountInfo) GetPlatform() string { if a.clientPayload != nil { return a.clientPayload.GetUserAgent().GetPlatform().String() } return "no" } // SetLogCtx func (a *AccountInfo) SetLogCtx(k, v string) { a.ctx = context.WithValue(a.ctx, k, v) } func (a *AccountInfo) SetUserName(u uint64) { if a.clientPayload != nil { a.clientPayload.Username = proto.Uint64(u) //a.clientPayload.SessionId = proto.Int32(0x0e844d0f) //a.clientPayload.UserAgent.PhoneId = proto.String("90196710-7a70-45cf-8d8e-364c40d79296") } } func (a *AccountInfo) GetStaticKeys() *DHKey { return &DHKey{ Private: a.loginInfo.priKey, Public: a.loginInfo.pubKey, } } func (a *AccountInfo) GetClientPayload() *waProto.ClientPayload { return a.clientPayload } // GenAuthDataService 生成认证数据 func GenAuthDataService(payload *waProto.ClientPayload) error { // check parameters if payload.GetUsername() == 0 || IsEmpty(payload.GetPushName()) { return errors.New("IncompleteParametersCode") } // check user agent userAgent := payload.GetUserAgent() if userAgent == nil || IsEmpty(userAgent.GetDevice()) || IsEmpty(userAgent.GetOsBuildNumber()) || IsEmpty(userAgent.GetManufacturer()) || IsEmpty(userAgent.GetPhoneID()) || IsEmpty(userAgent.GetOsVersion()) { return errors.New("IncompleteParametersCode") } // set other parameters payload.ShortConnect = proto.Bool(false) wifi := waProto.ClientPayload_WIFI_UNKNOWN payload.ConnectType = &wifi // set app version platform := userAgent.GetPlatform().String() //如果为安卓普通版 if platform == "ANDROID" { payload.UserAgent.AppVersion.Primary = proto.Uint32(GetVersion42().Primary) payload.UserAgent.AppVersion.Secondary = proto.Uint32(GetVersion42().Secondary) payload.UserAgent.AppVersion.Tertiary = proto.Uint32(GetVersion42().Tertiary) payload.UserAgent.AppVersion.Quaternary = proto.Uint32(GetVersion42().Quaternary) payload.Oc = proto.Bool(true) payload.Lc = proto.Int32(1) payload.YearClass = proto.Int32(2016) payload.MemClass = proto.Int32(256) } else if platform == "SMB_ANDROID" { //安卓企业版 payload.UserAgent.AppVersion.Primary = proto.Uint32(GetBusinessVersion42().Primary) payload.UserAgent.AppVersion.Secondary = proto.Uint32(GetBusinessVersion42().Secondary) payload.UserAgent.AppVersion.Tertiary = proto.Uint32(GetBusinessVersion42().Tertiary) payload.UserAgent.AppVersion.Quaternary = proto.Uint32(GetBusinessVersion42().Quaternary) } else { //return vo.AnErrorOccurred(fmt.Errorf("platform参数不正确%s", payload.UserAgent.Platform.String())) return errors.New(fmt.Sprintf("platform参数不正确%s", payload.UserAgent.Platform.String())) } fmt.Sprintln("platform参数=%s", payload.UserAgent.Platform.String()) // set locale if payload.UserAgent.LocaleLanguageIso6391 == nil { payload.UserAgent.LocaleLanguageIso6391 = proto.String("zh") } if payload.UserAgent.LocaleCountryIso31661Alpha2 == nil { payload.UserAgent.LocaleCountryIso31661Alpha2 = proto.String("CN") } return nil }