Browse Source

Reimplement more things

Tulir Asokan 3 years ago
parent
commit
433aaf3829
6 changed files with 88 additions and 75 deletions
  1. 46 33
      commands.go
  2. 1 1
      database/puppet.go
  3. 5 5
      database/statestore.go
  4. 2 2
      go.mod
  5. 4 4
      go.sum
  6. 30 30
      portal.go

+ 46 - 33
commands.go

@@ -323,6 +323,7 @@ func (handler *CommandHandler) CommandCreate(ce *CommandEvent) {
 	var roomNameEvent event.RoomNameEventContent
 	err = ce.Bot.StateEvent(ce.RoomID, event.StateRoomName, "", &roomNameEvent)
 	if err != nil && !errors.Is(err, mautrix.MNotFound) {
+		handler.log.Errorln("Failed to get room name to create group:", err)
 		ce.Reply("Failed to get room name")
 		return
 	} else if len(roomNameEvent.Name) == 0 {
@@ -337,45 +338,57 @@ func (handler *CommandHandler) CommandCreate(ce *CommandEvent) {
 		return
 	}
 
-	participants := []types.JID{ce.User.JID.ToNonAD()}
+	var participants []types.JID
+	participantDedup := make(map[types.JID]bool)
+	participantDedup[ce.User.JID.ToNonAD()] = true
+	participantDedup[types.EmptyJID] = true
 	for userID := range members.Joined {
 		jid, ok := handler.bridge.ParsePuppetMXID(userID)
-		if ok && jid.User != ce.User.JID.User {
+		if !ok {
+			user := handler.bridge.GetUserByMXID(userID)
+			if user != nil && !user.JID.IsEmpty() {
+				jid = user.JID.ToNonAD()
+			}
+		}
+		if !participantDedup[jid] {
+			participantDedup[jid] = true
 			participants = append(participants, jid)
 		}
 	}
 
-	ce.Reply("Not yet implemented")
-	// TODO reimplement
-	//resp, err := ce.User.Conn.CreateGroup(roomNameEvent.Name, participants)
-	//if err != nil {
-	//	ce.Reply("Failed to create group: %v", err)
-	//	return
-	//}
-	//portal := handler.bridge.GetPortalByJID(database.GroupPortalKey(resp.GroupID))
-	//portal.roomCreateLock.Lock()
-	//defer portal.roomCreateLock.Unlock()
-	//if len(portal.MXID) != 0 {
-	//	portal.log.Warnln("Detected race condition in room creation")
-	//	// TODO race condition, clean up the old room
-	//}
-	//portal.MXID = ce.RoomID
-	//portal.Name = roomNameEvent.Name
-	//portal.Encrypted = encryptionEvent.Algorithm == id.AlgorithmMegolmV1
-	//if !portal.Encrypted && handler.bridge.Config.Bridge.Encryption.Default {
-	//	_, err = portal.MainIntent().SendStateEvent(portal.MXID, event.StateEncryption, "", &event.EncryptionEventContent{Algorithm: id.AlgorithmMegolmV1})
-	//	if err != nil {
-	//		portal.log.Warnln("Failed to enable e2be:", err)
-	//	}
-	//	portal.Encrypted = true
-	//}
-	//
-	//portal.Update()
-	//portal.UpdateBridgeInfo()
-	//
-	//ce.Reply("Successfully created WhatsApp group %s", portal.Key.JID)
-	//inCommunity := ce.User.addPortalToCommunity(portal)
-	//ce.User.CreateUserPortal(database.PortalKeyWithMeta{PortalKey: portal.Key, InCommunity: inCommunity})
+	handler.log.Infofln("Creating group for %s with name %s and participants %+v", ce.RoomID, roomNameEvent.Name, participants)
+	resp, err := ce.User.Client.CreateGroup(roomNameEvent.Name, participants)
+	if err != nil {
+		ce.Reply("Failed to create group: %v", err)
+		return
+	}
+	portal := ce.User.GetPortalByJID(resp.JID)
+	portal.roomCreateLock.Lock()
+	defer portal.roomCreateLock.Unlock()
+	if len(portal.MXID) != 0 {
+		portal.log.Warnln("Detected race condition in room creation")
+		// TODO race condition, clean up the old room
+	}
+	portal.MXID = ce.RoomID
+	portal.Name = roomNameEvent.Name
+	portal.Encrypted = encryptionEvent.Algorithm == id.AlgorithmMegolmV1
+	if !portal.Encrypted && handler.bridge.Config.Bridge.Encryption.Default {
+		_, err = portal.MainIntent().SendStateEvent(portal.MXID, event.StateEncryption, "", &event.EncryptionEventContent{Algorithm: id.AlgorithmMegolmV1})
+		if err != nil {
+			portal.log.Warnln("Failed to enable encryption in room:", err)
+			if errors.Is(err, mautrix.MForbidden) {
+				ce.Reply("I don't seem to have permission to enable encryption in this room.")
+			} else {
+				ce.Reply("Failed to enable encryption in room: %v", err)
+			}
+		}
+		portal.Encrypted = true
+	}
+
+	portal.Update()
+	portal.UpdateBridgeInfo()
+
+	ce.Reply("Successfully created WhatsApp group %s", portal.Key.JID)
 }
 
 func parseInviteMeta(meta map[string]interface{}) (jid, inviter types.JID, code string, expiration int64, ok bool) {

+ 1 - 1
database/puppet.go

@@ -138,6 +138,6 @@ func (puppet *Puppet) Update() {
 	_, err := puppet.db.Exec("UPDATE puppet SET displayname=$1, name_quality=$2, avatar=$3, avatar_url=$4, custom_mxid=$5, access_token=$6, next_batch=$7, enable_presence=$8, enable_receipts=$9 WHERE username=$10",
 		puppet.Displayname, puppet.NameQuality, puppet.Avatar, puppet.AvatarURL.String(), puppet.CustomMXID, puppet.AccessToken, puppet.NextBatch, puppet.EnablePresence, puppet.EnableReceipts, puppet.JID.User)
 	if err != nil {
-		puppet.log.Warnfln("Failed to update %s->%s: %v", puppet.JID, err)
+		puppet.log.Warnfln("Failed to update %s: %v", puppet.JID, err)
 	}
 }

+ 5 - 5
database/statestore.go

@@ -218,13 +218,13 @@ func (store *SQLStateStore) GetPowerLevels(roomID id.RoomID) (levels *event.Powe
 	var data []byte
 	err := row.Scan(&data)
 	if err != nil {
-		store.log.Errorln("Failed to scan power levels of %s: %v", roomID, err)
+		store.log.Errorfln("Failed to scan power levels of %s: %v", roomID, err)
 		return
 	}
 	levels = &event.PowerLevelsEventContent{}
 	err = json.Unmarshal(data, levels)
 	if err != nil {
-		store.log.Errorln("Failed to parse power levels of %s: %v", roomID, err)
+		store.log.Errorfln("Failed to parse power levels of %s: %v", roomID, err)
 		return nil
 	}
 	return
@@ -242,7 +242,7 @@ func (store *SQLStateStore) GetPowerLevel(roomID id.RoomID, userID id.UserID) in
 		var powerLevel int
 		err := row.Scan(&powerLevel)
 		if err != nil {
-			store.log.Errorln("Failed to scan power level of %s in %s: %v", userID, roomID, err)
+			store.log.Errorfln("Failed to scan power level of %s in %s: %v", userID, roomID, err)
 		}
 		return powerLevel
 	}
@@ -267,7 +267,7 @@ func (store *SQLStateStore) GetPowerLevelRequirement(roomID id.RoomID, eventType
 		var powerLevel int
 		err := row.Scan(&powerLevel)
 		if err != nil {
-			store.log.Errorln("Failed to scan power level for %s in %s: %v", eventType, roomID, err)
+			store.log.Errorfln("Failed to scan power level for %s in %s: %v", eventType, roomID, err)
 		}
 		return powerLevel
 	}
@@ -294,7 +294,7 @@ func (store *SQLStateStore) HasPowerLevel(roomID id.RoomID, userID id.UserID, ev
 		var hasPower bool
 		err := row.Scan(&hasPower)
 		if err != nil {
-			store.log.Errorln("Failed to scan power level for %s in %s: %v", eventType, roomID, err)
+			store.log.Errorfln("Failed to scan power level for %s in %s: %v", eventType, roomID, err)
 		}
 		return hasPower
 	}

+ 2 - 2
go.mod

@@ -8,13 +8,13 @@ require (
 	github.com/mattn/go-sqlite3 v1.14.9
 	github.com/prometheus/client_golang v1.11.0
 	github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e
-	go.mau.fi/whatsmeow v0.0.0-20211103125516-00d0df2dd132
+	go.mau.fi/whatsmeow v0.0.0-20211105101612-33697884c521
 	golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d
 	google.golang.org/protobuf v1.27.1
 	gopkg.in/yaml.v2 v2.4.0
 	maunium.net/go/mauflag v1.0.0
 	maunium.net/go/maulogger/v2 v2.3.1
-	maunium.net/go/mautrix v0.10.1-0.20211103193019-010782c6021e
+	maunium.net/go/mautrix v0.10.1
 )
 
 require (

+ 4 - 4
go.sum

@@ -139,8 +139,8 @@ github.com/tidwall/sjson v1.2.3 h1:5+deguEhHSEjmuICXZ21uSSsXotWMA0orU783+Z7Cp8=
 github.com/tidwall/sjson v1.2.3/go.mod h1:5WdjKx3AQMvCJ4RG6/2UYT7dLrGvJUV1x4jdTAyGvZs=
 go.mau.fi/libsignal v0.0.0-20211024113310-f9fc6a1855f2 h1:xpQTMgJGGaF+c8jV/LA/FVXAPJxZbSAGeflOc+Ly6uQ=
 go.mau.fi/libsignal v0.0.0-20211024113310-f9fc6a1855f2/go.mod h1:3XlVlwOfp8f9Wri+C1D4ORqgUsN4ZvunJOoPjQMBhos=
-go.mau.fi/whatsmeow v0.0.0-20211103125516-00d0df2dd132 h1:wgpiQPdoKCTyhK/GfNfeNhbXjG5A3Fjkbfsmww6ojcY=
-go.mau.fi/whatsmeow v0.0.0-20211103125516-00d0df2dd132/go.mod h1:ODEmmqeUn9eBDQHFc1S902YA3YFLtmaBujYRRFl53jI=
+go.mau.fi/whatsmeow v0.0.0-20211105101612-33697884c521 h1:rkqvvX5qemi5DHMcwS5T/NmYBrzX3TAqKLW7P5lyHZg=
+go.mau.fi/whatsmeow v0.0.0-20211105101612-33697884c521/go.mod h1:ODEmmqeUn9eBDQHFc1S902YA3YFLtmaBujYRRFl53jI=
 golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
@@ -219,5 +219,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.3.1 h1:fwBYJne0pHvJrrIPHK+TAPfyxxbBEz46oVGez2x0ODE=
 maunium.net/go/maulogger/v2 v2.3.1/go.mod h1:TYWy7wKwz/tIXTpsx8G3mZseIRiC5DoMxSZazOHy68A=
-maunium.net/go/mautrix v0.10.1-0.20211103193019-010782c6021e h1:yvKCw2P/nHEfjvKAVA8aokbe1UYIgJcswnv50EZaSRU=
-maunium.net/go/mautrix v0.10.1-0.20211103193019-010782c6021e/go.mod h1:k4Ng5oci83MEbqPL6KOjPdbU7f8v01KlMjR/zTQ+7mA=
+maunium.net/go/mautrix v0.10.1 h1:sJeygU2CpvoeHKpCOLxUstclHG740IeBfTtKgKnC+nU=
+maunium.net/go/mautrix v0.10.1/go.mod h1:k4Ng5oci83MEbqPL6KOjPdbU7f8v01KlMjR/zTQ+7mA=

+ 30 - 30
portal.go

@@ -1423,10 +1423,10 @@ func (portal *Portal) HandleWhatsAppKick(source *User, senderJID types.JID, jids
 	sender := portal.bridge.GetPuppetByJID(senderJID)
 	senderIntent := sender.IntentFor(portal)
 	for _, jid := range jids {
-		if source != nil && source.JID.User == jid.User {
-			portal.log.Debugln("Ignoring self-kick by", source.MXID)
-			continue
-		}
+		//if source != nil && source.JID.User == jid.User {
+		//	portal.log.Debugln("Ignoring self-kick by", source.MXID)
+		//	continue
+		//}
 		puppet := portal.bridge.GetPuppetByJID(jid)
 		portal.removeUser(puppet.JID == sender.JID, senderIntent, puppet.MXID, puppet.DefaultIntent())
 
@@ -1452,7 +1452,8 @@ func (portal *Portal) leaveWithPuppetMeta(intent *appservice.IntentAPI) (*mautri
 			doublePuppetField: true,
 		},
 	}
-	return intent.SendStateEvent(portal.MXID, event.StateMember, intent.UserID.String(), &content)
+	// Bypass IntentAPI, we don't want to EnsureJoined here
+	return intent.Client.SendStateEvent(portal.MXID, event.StateMember, intent.UserID.String(), &content)
 }
 
 func (portal *Portal) HandleWhatsAppInvite(source *User, senderJID *types.JID, jids []types.JID) (evtID id.EventID) {
@@ -2250,13 +2251,11 @@ func (portal *Portal) HandleMatrixLeave(sender *User) {
 		portal.Cleanup(false)
 		return
 	} else if portal.bridge.Config.Bridge.BridgeMatrixLeave {
-		// TODO should we somehow deduplicate this call if this leave was sent by the bridge?
-		// FIXME reimplement
-		//resp, err := sender.Client.LeaveGroup(portal.Key.JID)
-		//if err != nil {
-		//	portal.log.Errorfln("Failed to leave group as %s: %v", sender.MXID, err)
-		//	return
-		//}
+		err := sender.Client.LeaveGroup(portal.Key.JID)
+		if err != nil {
+			portal.log.Errorfln("Failed to leave group as %s: %v", sender.MXID, err)
+			return
+		}
 		//portal.log.Infoln("Leave response:", <-resp)
 	}
 	portal.CleanupIfEmpty()
@@ -2265,12 +2264,13 @@ func (portal *Portal) HandleMatrixLeave(sender *User) {
 func (portal *Portal) HandleMatrixKick(sender *User, evt *event.Event) {
 	puppet := portal.bridge.GetPuppetByMXID(id.UserID(evt.GetStateKey()))
 	if puppet != nil {
-		// FIXME reimplement
-		//resp, err := sender.Conn.RemoveMember(portal.Key.JID, []string{puppet.JID})
-		//if err != nil {
-		//	portal.log.Errorfln("Failed to kick %s from group as %s: %v", puppet.JID, sender.MXID, err)
-		//	return
-		//}
+		_, err := sender.Client.UpdateGroupParticipants(portal.Key.JID, map[types.JID]whatsmeow.ParticipantChange{
+			puppet.JID: whatsmeow.ParticipantChangeRemove,
+		})
+		if err != nil {
+			portal.log.Errorfln("Failed to kick %s from group as %s: %v", puppet.JID, sender.MXID, err)
+			return
+		}
 		//portal.log.Infoln("Kick %s response: %s", puppet.JID, <-resp)
 	}
 }
@@ -2278,12 +2278,13 @@ func (portal *Portal) HandleMatrixKick(sender *User, evt *event.Event) {
 func (portal *Portal) HandleMatrixInvite(sender *User, evt *event.Event) {
 	puppet := portal.bridge.GetPuppetByMXID(id.UserID(evt.GetStateKey()))
 	if puppet != nil {
-		// FIXME reimplement
-		//resp, err := sender.Conn.AddMember(portal.Key.JID, []string{puppet.JID})
-		//if err != nil {
-		//	portal.log.Errorfln("Failed to add %s to group as %s: %v", puppet.JID, sender.MXID, err)
-		//	return
-		//}
+		_, err := sender.Client.UpdateGroupParticipants(portal.Key.JID, map[types.JID]whatsmeow.ParticipantChange{
+			puppet.JID: whatsmeow.ParticipantChangeAdd,
+		})
+		if err != nil {
+			portal.log.Errorfln("Failed to add %s to group as %s: %v", puppet.JID, sender.MXID, err)
+			return
+		}
 		//portal.log.Infofln("Add %s response: %s", puppet.JID, <-resp)
 	}
 }
@@ -2295,17 +2296,16 @@ func (portal *Portal) HandleMatrixMeta(sender *User, evt *event.Event) {
 		if content.Name == portal.Name {
 			return
 		}
-		// FIXME reimplement
-		//portal.Name = content.Name
-		//resp, err = sender.Conn.UpdateGroupSubject(content.Name, portal.Key.JID)
+		portal.Name = content.Name
+		err = sender.Client.SetGroupName(portal.Key.JID, content.Name)
 	case *event.TopicEventContent:
 		if content.Topic == portal.Topic {
 			return
 		}
-		// FIXME reimplement
-		//portal.Topic = content.Topic
-		//resp, err = sender.Conn.UpdateGroupDescription(sender.JID, portal.Key.JID, content.Topic)
+		portal.Topic = content.Topic
+		err = sender.Client.SetGroupTopic(portal.Key.JID, "", "", content.Topic)
 	case *event.RoomAvatarEventContent:
+		// TODO implement
 		return
 	}
 	if err != nil {