diff --git a/database/puppet.go b/database/puppet.go index 806df8d..17d7996 100644 --- a/database/puppet.go +++ b/database/puppet.go @@ -44,7 +44,7 @@ func (pq *PuppetQuery) New() *Puppet { } func (pq *PuppetQuery) GetAll() (puppets []*Puppet) { - rows, err := pq.db.Query("SELECT username, avatar, avatar_url, displayname, name_quality, name_set, avatar_set, last_sync, custom_mxid, access_token, next_batch, enable_presence, enable_receipts FROM puppet") + rows, err := pq.db.Query("SELECT username, avatar, avatar_url, displayname, name_quality, name_set, avatar_set, contact_info_set, last_sync, custom_mxid, access_token, next_batch, enable_presence, enable_receipts FROM puppet") if err != nil || rows == nil { return nil } @@ -56,7 +56,7 @@ func (pq *PuppetQuery) GetAll() (puppets []*Puppet) { } func (pq *PuppetQuery) Get(jid types.JID) *Puppet { - row := pq.db.QueryRow("SELECT username, avatar, avatar_url, displayname, name_quality, name_set, avatar_set, last_sync, custom_mxid, access_token, next_batch, enable_presence, enable_receipts FROM puppet WHERE username=$1", jid.User) + row := pq.db.QueryRow("SELECT username, avatar, avatar_url, displayname, name_quality, name_set, avatar_set, contact_info_set, last_sync, custom_mxid, access_token, next_batch, enable_presence, enable_receipts FROM puppet WHERE username=$1", jid.User) if row == nil { return nil } @@ -64,7 +64,7 @@ func (pq *PuppetQuery) Get(jid types.JID) *Puppet { } func (pq *PuppetQuery) GetByCustomMXID(mxid id.UserID) *Puppet { - row := pq.db.QueryRow("SELECT username, avatar, avatar_url, displayname, name_quality, name_set, avatar_set, last_sync, custom_mxid, access_token, next_batch, enable_presence, enable_receipts FROM puppet WHERE custom_mxid=$1", mxid) + row := pq.db.QueryRow("SELECT username, avatar, avatar_url, displayname, name_quality, name_set, avatar_set, contact_info_set, last_sync, custom_mxid, access_token, next_batch, enable_presence, enable_receipts FROM puppet WHERE custom_mxid=$1", mxid) if row == nil { return nil } @@ -72,7 +72,7 @@ func (pq *PuppetQuery) GetByCustomMXID(mxid id.UserID) *Puppet { } func (pq *PuppetQuery) GetAllWithCustomMXID() (puppets []*Puppet) { - rows, err := pq.db.Query("SELECT username, avatar, avatar_url, displayname, name_quality, name_set, avatar_set, last_sync, custom_mxid, access_token, next_batch, enable_presence, enable_receipts FROM puppet WHERE custom_mxid<>''") + rows, err := pq.db.Query("SELECT username, avatar, avatar_url, displayname, name_quality, name_set, avatar_set, contact_info_set, last_sync, custom_mxid, access_token, next_batch, enable_presence, enable_receipts FROM puppet WHERE custom_mxid<>''") if err != nil || rows == nil { return nil } @@ -87,14 +87,15 @@ type Puppet struct { db *Database log log.Logger - JID types.JID - Avatar string - AvatarURL id.ContentURI - AvatarSet bool - Displayname string - NameQuality int8 - NameSet bool - LastSync time.Time + JID types.JID + Avatar string + AvatarURL id.ContentURI + AvatarSet bool + Displayname string + NameQuality int8 + NameSet bool + ContactInfoSet bool + LastSync time.Time CustomMXID id.UserID AccessToken string @@ -106,9 +107,9 @@ type Puppet struct { func (puppet *Puppet) Scan(row dbutil.Scannable) *Puppet { var displayname, avatar, avatarURL, customMXID, accessToken, nextBatch sql.NullString var quality, lastSync sql.NullInt64 - var enablePresence, enableReceipts, nameSet, avatarSet sql.NullBool + var enablePresence, enableReceipts, nameSet, avatarSet, contactInfoSet sql.NullBool var username string - err := row.Scan(&username, &avatar, &avatarURL, &displayname, &quality, &nameSet, &avatarSet, &lastSync, &customMXID, &accessToken, &nextBatch, &enablePresence, &enableReceipts) + err := row.Scan(&username, &avatar, &avatarURL, &displayname, &quality, &nameSet, &avatarSet, &contactInfoSet, &lastSync, &customMXID, &accessToken, &nextBatch, &enablePresence, &enableReceipts) if err != nil { if err != sql.ErrNoRows { puppet.log.Errorln("Database scan failed:", err) @@ -122,6 +123,7 @@ func (puppet *Puppet) Scan(row dbutil.Scannable) *Puppet { puppet.NameQuality = int8(quality.Int64) puppet.NameSet = nameSet.Bool puppet.AvatarSet = avatarSet.Bool + puppet.ContactInfoSet = contactInfoSet.Bool if lastSync.Int64 > 0 { puppet.LastSync = time.Unix(lastSync.Int64, 0) } @@ -143,11 +145,11 @@ func (puppet *Puppet) Insert() { lastSyncTs = puppet.LastSync.Unix() } _, err := puppet.db.Exec(` - INSERT INTO puppet (username, avatar, avatar_url, avatar_set, displayname, name_quality, name_set, last_sync, - custom_mxid, access_token, next_batch, enable_presence, enable_receipts) - VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) + INSERT INTO puppet (username, avatar, avatar_url, avatar_set, displayname, name_quality, name_set, contact_info_set, + last_sync, custom_mxid, access_token, next_batch, enable_presence, enable_receipts) + VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14) `, puppet.JID.User, puppet.Avatar, puppet.AvatarURL.String(), puppet.AvatarSet, puppet.Displayname, - puppet.NameQuality, puppet.NameSet, lastSyncTs, puppet.CustomMXID, puppet.AccessToken, puppet.NextBatch, + puppet.NameQuality, puppet.NameSet, puppet.ContactInfoSet, lastSyncTs, puppet.CustomMXID, puppet.AccessToken, puppet.NextBatch, puppet.EnablePresence, puppet.EnableReceipts, ) if err != nil { @@ -162,10 +164,10 @@ func (puppet *Puppet) Update() { } _, err := puppet.db.Exec(` UPDATE puppet - SET displayname=$1, name_quality=$2, name_set=$3, avatar=$4, avatar_url=$5, avatar_set=$6, last_sync=$7, - custom_mxid=$8, access_token=$9, next_batch=$10, enable_presence=$11, enable_receipts=$12 - WHERE username=$13 - `, puppet.Displayname, puppet.NameQuality, puppet.NameSet, puppet.Avatar, puppet.AvatarURL.String(), puppet.AvatarSet, + SET displayname=$1, name_quality=$2, name_set=$3, avatar=$4, avatar_url=$5, avatar_set=$6, contact_info_set=$7, last_sync=$8, + custom_mxid=$9, access_token=$10, next_batch=$11, enable_presence=$12, enable_receipts=$13 + WHERE username=$14 + `, puppet.Displayname, puppet.NameQuality, puppet.NameSet, puppet.Avatar, puppet.AvatarURL.String(), puppet.AvatarSet, puppet.ContactInfoSet, lastSyncTs, puppet.CustomMXID, puppet.AccessToken, puppet.NextBatch, puppet.EnablePresence, puppet.EnableReceipts, puppet.JID.User) if err != nil { diff --git a/database/upgrades/00-latest-revision.sql b/database/upgrades/00-latest-revision.sql index 7612b92..f4f649d 100644 --- a/database/upgrades/00-latest-revision.sql +++ b/database/upgrades/00-latest-revision.sql @@ -1,4 +1,4 @@ --- v0 -> v54: Latest revision +-- v0 -> v55: Latest revision CREATE TABLE "user" ( mxid TEXT PRIMARY KEY, @@ -43,14 +43,15 @@ CREATE TABLE portal ( CREATE INDEX portal_parent_group_idx ON portal(parent_group); CREATE TABLE puppet ( - username TEXT PRIMARY KEY, - displayname TEXT, - name_quality SMALLINT, - avatar TEXT, - avatar_url TEXT, - name_set BOOLEAN NOT NULL DEFAULT false, - avatar_set BOOLEAN NOT NULL DEFAULT false, - last_sync BIGINT NOT NULL DEFAULT 0, + username TEXT PRIMARY KEY, + displayname TEXT, + name_quality SMALLINT, + avatar TEXT, + avatar_url TEXT, + name_set BOOLEAN NOT NULL DEFAULT false, + avatar_set BOOLEAN NOT NULL DEFAULT false, + contact_info_set BOOLEAN NOT NULL DEFAULT false, + last_sync BIGINT NOT NULL DEFAULT 0, custom_mxid TEXT, access_token TEXT, diff --git a/database/upgrades/55-add-contact-info.sql b/database/upgrades/55-add-contact-info.sql new file mode 100644 index 0000000..db85a13 --- /dev/null +++ b/database/upgrades/55-add-contact-info.sql @@ -0,0 +1,3 @@ +-- v55: Store whether custom contact info has been set for a puppet + +ALTER TABLE puppet ADD COLUMN contact_info_set BOOLEAN NOT NULL DEFAULT false; diff --git a/go.mod b/go.mod index c189b69..1c57642 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( golang.org/x/net v0.8.0 google.golang.org/protobuf v1.28.1 maunium.net/go/maulogger/v2 v2.4.1 - maunium.net/go/mautrix v0.15.1-0.20230405144343-a47718edca66 + maunium.net/go/mautrix v0.15.1-0.20230407141116-e5aa88ba0f9d ) require ( diff --git a/go.sum b/go.sum index 1affe10..5028d16 100644 --- a/go.sum +++ b/go.sum @@ -134,5 +134,5 @@ maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M= maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA= maunium.net/go/maulogger/v2 v2.4.1 h1:N7zSdd0mZkB2m2JtFUsiGTQQAdP0YeFWT7YMc80yAL8= maunium.net/go/maulogger/v2 v2.4.1/go.mod h1:omPuYwYBILeVQobz8uO3XC8DIRuEb5rXYlQSuqrbCho= -maunium.net/go/mautrix v0.15.1-0.20230405144343-a47718edca66 h1:P+UbO87hsxpY0HyzAS36VmzuEqz/vzhmO0wClaAlxl0= -maunium.net/go/mautrix v0.15.1-0.20230405144343-a47718edca66/go.mod h1:Ei+ijYIMoQ3at2vJrMbEQq/pN2fB3h18clD8PyVyTD0= +maunium.net/go/mautrix v0.15.1-0.20230407141116-e5aa88ba0f9d h1:LdxNYgiE2J7Q2057MV30ogMHiivhLPU02aTVbcqQeC8= +maunium.net/go/mautrix v0.15.1-0.20230407141116-e5aa88ba0f9d/go.mod h1:Ei+ijYIMoQ3at2vJrMbEQq/pN2fB3h18clD8PyVyTD0= diff --git a/main.go b/main.go index 67734a0..3d07a51 100644 --- a/main.go +++ b/main.go @@ -151,6 +151,7 @@ func (br *WABridge) Start() { br.Provisioning.Init() } go br.CheckWhatsAppUpdate() + go br.UpdatePuppetContactInfo() go br.StartUsers() if br.Config.Metrics.Enabled { go br.Metrics.Start() @@ -181,6 +182,14 @@ func (br *WABridge) CheckWhatsAppUpdate() { } } +func (br *WABridge) UpdatePuppetContactInfo() { + for _, puppet := range br.GetAllPuppets() { + if puppet.UpdateContactInfo() { + puppet.Update() + } + } +} + func (br *WABridge) Loop() { for { br.SleepAndDeleteUpcoming() @@ -273,11 +282,13 @@ func main() { puppetsByCustomMXID: make(map[id.UserID]*Puppet), } br.Bridge = bridge.Bridge{ - Name: "mautrix-whatsapp", - URL: "https://github.com/mautrix/whatsapp", - Description: "A Matrix-WhatsApp puppeting bridge.", - Version: "0.8.3", - ProtocolName: "WhatsApp", + Name: "mautrix-whatsapp", + URL: "https://github.com/mautrix/whatsapp", + Description: "A Matrix-WhatsApp puppeting bridge.", + Version: "0.8.3", + ProtocolName: "WhatsApp", + BeeperServiceName: "whatsapp", + BeeperNetworkName: "whatsapp", CryptoPickleKey: "maunium.net/go/mautrix-whatsapp", diff --git a/puppet.go b/puppet.go index 2895642..137aebf 100644 --- a/puppet.go +++ b/puppet.go @@ -28,6 +28,7 @@ import ( "maunium.net/go/mautrix/appservice" "maunium.net/go/mautrix/bridge" + "maunium.net/go/mautrix/bridge/bridgeconfig" "maunium.net/go/mautrix/id" "maunium.net/go/mautrix-whatsapp/config" @@ -262,6 +263,36 @@ func (puppet *Puppet) UpdateName(contact types.ContactInfo, forcePortalSync bool return false } +func (puppet *Puppet) UpdateContactInfo() bool { + if puppet.bridge.Config.Homeserver.Software != bridgeconfig.SoftwareHungry { + return false + } + + if puppet.ContactInfoSet { + return false + } + + contactInfo := map[string]any{ + "com.beeper.bridge.identifiers": []string{ + fmt.Sprintf("tel:+%s", puppet.JID.User), + fmt.Sprintf("whatsapp:%s", puppet.JID.String()), + }, + "com.beeper.bridge.remote_id": puppet.JID.String(), + "com.beeper.bridge.service": "whatsapp", + "com.beeper.bridge.network": "whatsapp", + "com.beeper.bridge.is_bridge_bot": false, + "com.beeper.bridge.is_bot": false, + } + err := puppet.DefaultIntent().BeeperUpdateProfile(contactInfo) + if err != nil { + puppet.log.Warnln("Failed to store custom contact info in profile:", err) + return false + } else { + puppet.ContactInfoSet = true + return true + } +} + func (puppet *Puppet) updatePortalMeta(meta func(portal *Portal)) { if puppet.bridge.Config.Bridge.PrivateChatPortalMeta || puppet.bridge.Config.Bridge.Encryption.Allow { for _, portal := range puppet.bridge.GetAllPortalsByJID(puppet.JID) { @@ -338,6 +369,7 @@ func (puppet *Puppet) Sync(source *User, contact *types.ContactInfo, forceAvatar if len(puppet.Avatar) == 0 || forceAvatarSync || puppet.bridge.Config.Bridge.UserAvatarSync { update = puppet.UpdateAvatar(source, forcePortalSync) || update } + update = puppet.UpdateContactInfo() || update if update || puppet.LastSync.Add(24*time.Hour).Before(time.Now()) { puppet.LastSync = time.Now() puppet.Update()