summaryrefslogtreecommitdiffstats
path: root/vendor/go.mau.fi/whatsmeow/store
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/go.mau.fi/whatsmeow/store')
-rw-r--r--vendor/go.mau.fi/whatsmeow/store/clientpayload.go96
-rw-r--r--vendor/go.mau.fi/whatsmeow/store/sqlstore/store.go90
-rw-r--r--vendor/go.mau.fi/whatsmeow/store/store.go9
3 files changed, 170 insertions, 25 deletions
diff --git a/vendor/go.mau.fi/whatsmeow/store/clientpayload.go b/vendor/go.mau.fi/whatsmeow/store/clientpayload.go
index 81519ee2..675719a2 100644
--- a/vendor/go.mau.fi/whatsmeow/store/clientpayload.go
+++ b/vendor/go.mau.fi/whatsmeow/store/clientpayload.go
@@ -20,36 +20,98 @@ import (
waProto "go.mau.fi/whatsmeow/binary/proto"
)
+// 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() *waProto.AppVersion {
+ return &waProto.AppVersion{
+ Primary: &vc[0],
+ Secondary: &vc[1],
+ Tertiary: &vc[2],
+ }
+}
+
// waVersion is the WhatsApp web client version
-var waVersion = []uint32{2, 2202, 9}
+var waVersion = WAVersionContainer{2, 2208, 7}
// waVersionHash is the md5 hash of a dot-separated waVersion
var waVersionHash [16]byte
func init() {
- waVersionParts := make([]string, len(waVersion))
- for i, part := range waVersion {
- waVersionParts[i] = strconv.Itoa(int(part))
+ 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
}
- waVersionString := strings.Join(waVersionParts, ".")
- waVersionHash = md5.Sum([]byte(waVersionString))
+ waVersion = version
+ waVersionHash = version.Hash()
}
var BaseClientPayload = &waProto.ClientPayload{
UserAgent: &waProto.UserAgent{
Platform: waProto.UserAgent_WEB.Enum(),
ReleaseChannel: waProto.UserAgent_RELEASE.Enum(),
- AppVersion: &waProto.AppVersion{
- Primary: &waVersion[0],
- Secondary: &waVersion[1],
- Tertiary: &waVersion[2],
- },
- Mcc: proto.String("000"),
- Mnc: proto.String("000"),
- OsVersion: proto.String("0.1.0"),
- Manufacturer: proto.String(""),
- Device: proto.String("Desktop"),
- OsBuildNumber: proto.String("0.1.0"),
+ AppVersion: waVersion.ProtoAppVersion(),
+ Mcc: proto.String("000"),
+ Mnc: proto.String("000"),
+ OsVersion: proto.String("0.1.0"),
+ Manufacturer: proto.String(""),
+ Device: proto.String("Desktop"),
+ OsBuildNumber: proto.String("0.1.0"),
+
LocaleLanguageIso6391: proto.String("en"),
LocaleCountryIso31661Alpha2: proto.String("en"),
},
diff --git a/vendor/go.mau.fi/whatsmeow/store/sqlstore/store.go b/vendor/go.mau.fi/whatsmeow/store/sqlstore/store.go
index ad1eea7e..01ec2056 100644
--- a/vendor/go.mau.fi/whatsmeow/store/sqlstore/store.go
+++ b/vendor/go.mau.fi/whatsmeow/store/sqlstore/store.go
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 Tulir Asokan
+// Copyright (c) 2022 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
@@ -349,15 +349,15 @@ func (s *SQLStore) putAppStateMutationMACs(tx execable, name string, version uin
values[0] = s.JID
values[1] = name
values[2] = version
+ placeholderSyntax := "($1, $2, $3, $%d, $%d)"
+ if s.dialect == "sqlite3" {
+ placeholderSyntax = "(?1, ?2, ?3, ?%d, ?%d)"
+ }
for i, mutation := range mutations {
baseIndex := 3 + i*2
values[baseIndex] = mutation.IndexMAC
values[baseIndex+1] = mutation.ValueMAC
- if s.dialect == "sqlite3" {
- queryParts[i] = fmt.Sprintf("(?1, ?2, ?3, ?%d, ?%d)", baseIndex+1, baseIndex+2)
- } else {
- queryParts[i] = fmt.Sprintf("($1, $2, $3, $%d, $%d)", baseIndex+1, baseIndex+2)
- }
+ queryParts[i] = fmt.Sprintf(placeholderSyntax, baseIndex+1, baseIndex+2)
}
_, err := tx.Exec(putAppStateMutationMACsQuery+strings.Join(queryParts, ","), values...)
return err
@@ -426,7 +426,12 @@ func (s *SQLStore) GetAppStateMutationMAC(name string, indexMAC []byte) (valueMA
const (
putContactNameQuery = `
INSERT INTO whatsmeow_contacts (our_jid, their_jid, first_name, full_name) VALUES ($1, $2, $3, $4)
- ON CONFLICT (our_jid, their_jid) DO UPDATE SET first_name=$3, full_name=$4
+ ON CONFLICT (our_jid, their_jid) DO UPDATE SET first_name=excluded.first_name, full_name=excluded.full_name
+ `
+ putManyContactNamesQuery = `
+ INSERT INTO whatsmeow_contacts (our_jid, their_jid, first_name, full_name)
+ VALUES %s
+ ON CONFLICT (our_jid, their_jid) DO UPDATE SET first_name=excluded.first_name, full_name=excluded.full_name
`
putPushNameQuery = `
INSERT INTO whatsmeow_contacts (our_jid, their_jid, push_name) VALUES ($1, $2, $3)
@@ -504,6 +509,77 @@ func (s *SQLStore) PutContactName(user types.JID, firstName, fullName string) er
return nil
}
+const contactBatchSize = 300
+
+func (s *SQLStore) putContactNamesBatch(tx execable, contacts []store.ContactEntry) error {
+ values := make([]interface{}, 1, 1+len(contacts)*3)
+ queryParts := make([]string, 0, len(contacts))
+ values[0] = s.JID
+ placeholderSyntax := "($1, $%d, $%d, $%d)"
+ if s.dialect == "sqlite3" {
+ placeholderSyntax = "(?1, ?%d, ?%d, ?%d)"
+ }
+ i := 0
+ handledContacts := make(map[types.JID]struct{}, len(contacts))
+ for _, contact := range contacts {
+ if contact.JID.IsEmpty() {
+ s.log.Warnf("Empty contact info in mass insert: %+v", contact)
+ continue
+ }
+ // The whole query will break if there are duplicates, so make sure there aren't any duplicates
+ _, alreadyHandled := handledContacts[contact.JID]
+ if alreadyHandled {
+ s.log.Warnf("Duplicate contact info for %s in mass insert", contact.JID)
+ continue
+ }
+ handledContacts[contact.JID] = struct{}{}
+ baseIndex := i*3 + 1
+ values = append(values, contact.JID.String(), contact.FirstName, contact.FullName)
+ queryParts = append(queryParts, fmt.Sprintf(placeholderSyntax, baseIndex+1, baseIndex+2, baseIndex+3))
+ i++
+ }
+ _, err := tx.Exec(fmt.Sprintf(putManyContactNamesQuery, strings.Join(queryParts, ",")), values...)
+ return err
+}
+
+func (s *SQLStore) PutAllContactNames(contacts []store.ContactEntry) error {
+ if len(contacts) > contactBatchSize {
+ tx, err := s.db.Begin()
+ if err != nil {
+ return fmt.Errorf("failed to start transaction: %w", err)
+ }
+ for i := 0; i < len(contacts); i += contactBatchSize {
+ var contactSlice []store.ContactEntry
+ if len(contacts) > i+contactBatchSize {
+ contactSlice = contacts[i : i+contactBatchSize]
+ } else {
+ contactSlice = contacts[i:]
+ }
+ err = s.putContactNamesBatch(tx, contactSlice)
+ if err != nil {
+ _ = tx.Rollback()
+ return err
+ }
+ }
+ err = tx.Commit()
+ if err != nil {
+ return fmt.Errorf("failed to commit transaction: %w", err)
+ }
+ } else if len(contacts) > 0 {
+ err := s.putContactNamesBatch(s.db, contacts)
+ if err != nil {
+ return err
+ }
+ } else {
+ return nil
+ }
+ s.contactCacheLock.Lock()
+ // Just clear the cache, fetching pushnames and business names would be too much effort
+ s.contactCache = make(map[types.JID]*types.ContactInfo)
+ s.contactCacheLock.Unlock()
+ return nil
+}
+
func (s *SQLStore) getContact(user types.JID) (*types.ContactInfo, error) {
cached, ok := s.contactCache[user]
if ok {
diff --git a/vendor/go.mau.fi/whatsmeow/store/store.go b/vendor/go.mau.fi/whatsmeow/store/store.go
index 65624b9f..67fe38fa 100644
--- a/vendor/go.mau.fi/whatsmeow/store/store.go
+++ b/vendor/go.mau.fi/whatsmeow/store/store.go
@@ -1,4 +1,4 @@
-// Copyright (c) 2021 Tulir Asokan
+// Copyright (c) 2022 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
@@ -71,10 +71,17 @@ type AppStateStore interface {
GetAppStateMutationMAC(name string, indexMAC []byte) (valueMAC []byte, err error)
}
+type ContactEntry struct {
+ JID types.JID
+ FirstName string
+ FullName string
+}
+
type ContactStore interface {
PutPushName(user types.JID, pushName string) (bool, string, error)
PutBusinessName(user types.JID, businessName string) error
PutContactName(user types.JID, fullName, firstName string) error
+ PutAllContactNames(contacts []ContactEntry) error
GetContact(user types.JID) (types.ContactInfo, error)
GetAllContacts() (map[types.JID]types.ContactInfo, error)
}