| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- // Copyright (c) 2021 Tulir Asokan
- //
- // This Source Code Form is subject to the terms of the Mozilla Public
- // License, v. 2.0. If a copy of the MPL was not distributed with this
- // file, You can obtain one at http://mozilla.org/MPL/2.0/.
- package store
- import (
- "crypto/md5"
- "encoding/binary"
- "fmt"
- "strconv"
- "strings"
- "google.golang.org/protobuf/proto"
- "go.mau.fi/libsignal/ecc"
- "go.mau.fi/whatsmeow/proto/waCompanionReg"
- "go.mau.fi/whatsmeow/proto/waWa6"
- "go.mau.fi/whatsmeow/types"
- )
- // WAVersionContainer is a container for a WhatsApp web version number.
- type WAVersionContainer [3]uint32
- // ParseVersion parses a version string (three dot-separated numbers) into a WAVersionContainer.
- func ParseVersion(version string) (parsed WAVersionContainer, err error) {
- var part1, part2, part3 int
- if parts := strings.Split(version, "."); len(parts) != 3 {
- err = fmt.Errorf("'%s' doesn't contain three dot-separated parts", version)
- } else if part1, err = strconv.Atoi(parts[0]); err != nil {
- err = fmt.Errorf("first part of '%s' is not a number: %w", version, err)
- } else if part2, err = strconv.Atoi(parts[1]); err != nil {
- err = fmt.Errorf("second part of '%s' is not a number: %w", version, err)
- } else if part3, err = strconv.Atoi(parts[2]); err != nil {
- err = fmt.Errorf("third part of '%s' is not a number: %w", version, err)
- } else {
- parsed = WAVersionContainer{uint32(part1), uint32(part2), uint32(part3)}
- }
- return
- }
- func (vc WAVersionContainer) LessThan(other WAVersionContainer) bool {
- return vc[0] < other[0] ||
- (vc[0] == other[0] && vc[1] < other[1]) ||
- (vc[0] == other[0] && vc[1] == other[1] && vc[2] < other[2])
- }
- // IsZero returns true if the version is zero.
- func (vc WAVersionContainer) IsZero() bool {
- return vc == [3]uint32{0, 0, 0}
- }
- // String returns the version number as a dot-separated string.
- func (vc WAVersionContainer) String() string {
- parts := make([]string, len(vc))
- for i, part := range vc {
- parts[i] = strconv.Itoa(int(part))
- }
- return strings.Join(parts, ".")
- }
- // Hash returns the md5 hash of the String representation of this version.
- func (vc WAVersionContainer) Hash() [16]byte {
- return md5.Sum([]byte(vc.String()))
- }
- func (vc WAVersionContainer) ProtoAppVersion() *waWa6.ClientPayload_UserAgent_AppVersion {
- return &waWa6.ClientPayload_UserAgent_AppVersion{
- Primary: &vc[0],
- Secondary: &vc[1],
- Tertiary: &vc[2],
- }
- }
- // waVersion is the WhatsApp web client version
- var waVersion = WAVersionContainer{2, 3000, 1030403648}
- // waVersionHash is the md5 hash of a dot-separated waVersion
- var waVersionHash [16]byte
- func init() {
- waVersionHash = waVersion.Hash()
- }
- // GetWAVersion gets the current WhatsApp web client version.
- func GetWAVersion() WAVersionContainer {
- return waVersion
- }
- // SetWAVersion sets the current WhatsApp web client version.
- //
- // In general, you should keep the library up-to-date instead of using this,
- // as there may be code changes that are necessary too (like protobuf schema changes).
- func SetWAVersion(version WAVersionContainer) {
- if version.IsZero() {
- return
- }
- waVersion = version
- waVersionHash = version.Hash()
- }
- var BaseClientPayload = &waWa6.ClientPayload{
- UserAgent: &waWa6.ClientPayload_UserAgent{
- Platform: waWa6.ClientPayload_UserAgent_WEB.Enum(),
- ReleaseChannel: waWa6.ClientPayload_UserAgent_RELEASE.Enum(),
- AppVersion: waVersion.ProtoAppVersion(),
- Mcc: proto.String("000"),
- Mnc: proto.String("000"),
- OsVersion: proto.String("0.1"),
- Manufacturer: proto.String(""),
- Device: proto.String("Desktop"),
- OsBuildNumber: proto.String("0.1"),
- LocaleLanguageIso6391: proto.String("en"),
- LocaleCountryIso31661Alpha2: proto.String("US"),
- },
- WebInfo: &waWa6.ClientPayload_WebInfo{
- WebSubPlatform: waWa6.ClientPayload_WebInfo_WEB_BROWSER.Enum(),
- },
- ConnectType: waWa6.ClientPayload_WIFI_UNKNOWN.Enum(),
- ConnectReason: waWa6.ClientPayload_USER_ACTIVATED.Enum(),
- }
- var DeviceProps = &waCompanionReg.DeviceProps{
- Os: proto.String("whatsmeow"),
- Version: &waCompanionReg.DeviceProps_AppVersion{
- Primary: proto.Uint32(0),
- Secondary: proto.Uint32(1),
- Tertiary: proto.Uint32(0),
- },
- HistorySyncConfig: &waCompanionReg.DeviceProps_HistorySyncConfig{
- StorageQuotaMb: proto.Uint32(10240),
- InlineInitialPayloadInE2EeMsg: proto.Bool(true),
- RecentSyncDaysLimit: nil,
- SupportCallLogHistory: proto.Bool(false),
- SupportBotUserAgentChatHistory: proto.Bool(true),
- SupportCagReactionsAndPolls: proto.Bool(true),
- SupportBizHostedMsg: proto.Bool(true),
- SupportRecentSyncChunkMessageCountTuning: proto.Bool(true),
- SupportHostedGroupMsg: proto.Bool(true),
- SupportFbidBotChatHistory: proto.Bool(true),
- SupportAddOnHistorySyncMigration: nil,
- SupportMessageAssociation: proto.Bool(true),
- SupportGroupHistory: proto.Bool(false),
- OnDemandReady: nil,
- SupportGuestChat: nil,
- CompleteOnDemandReady: nil,
- ThumbnailSyncDaysLimit: nil,
- },
- PlatformType: waCompanionReg.DeviceProps_UNKNOWN.Enum(),
- RequireFullSync: proto.Bool(false),
- }
- func SetOSInfo(name string, version [3]uint32) {
- DeviceProps.Os = &name
- DeviceProps.Version.Primary = &version[0]
- DeviceProps.Version.Secondary = &version[1]
- DeviceProps.Version.Tertiary = &version[2]
- BaseClientPayload.UserAgent.OsVersion = proto.String(fmt.Sprintf("%d.%d.%d", version[0], version[1], version[2]))
- BaseClientPayload.UserAgent.OsBuildNumber = BaseClientPayload.UserAgent.OsVersion
- }
- func (device *Device) getRegistrationPayload() *waWa6.ClientPayload {
- payload := proto.Clone(BaseClientPayload).(*waWa6.ClientPayload)
- regID := make([]byte, 4)
- binary.BigEndian.PutUint32(regID, device.RegistrationID)
- preKeyID := make([]byte, 4)
- binary.BigEndian.PutUint32(preKeyID, device.SignedPreKey.KeyID)
- deviceProps, _ := proto.Marshal(DeviceProps)
- payload.DevicePairingData = &waWa6.ClientPayload_DevicePairingRegistrationData{
- ERegid: regID,
- EKeytype: []byte{ecc.DjbType},
- EIdent: device.IdentityKey.Pub[:],
- ESkeyID: preKeyID[1:],
- ESkeyVal: device.SignedPreKey.Pub[:],
- ESkeySig: device.SignedPreKey.Signature[:],
- BuildHash: waVersionHash[:],
- DeviceProps: deviceProps,
- }
- payload.Passive = proto.Bool(false)
- payload.Pull = proto.Bool(false)
- return payload
- }
- func (device *Device) getLoginPayload() *waWa6.ClientPayload {
- payload := proto.Clone(BaseClientPayload).(*waWa6.ClientPayload)
- payload.Username = proto.Uint64(device.ID.UserInt())
- payload.Device = proto.Uint32(uint32(device.ID.Device))
- payload.Passive = proto.Bool(true)
- payload.Pull = proto.Bool(true)
- payload.LidDbMigrated = proto.Bool(true)
- return payload
- }
- func (device *Device) GetClientPayload() *waWa6.ClientPayload {
- if device.ID != nil {
- if device.Mobile {
- return device.ClientPayload
- }
- if *device.ID == types.EmptyJID {
- panic(fmt.Errorf("GetClientPayload called with empty JID"))
- }
- return device.getLoginPayload()
- } else {
- return device.getRegistrationPayload()
- }
- }
|