From 74698a0e005a9da299a65bc3a1462c1c85aad330 Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Thu, 12 May 2022 15:15:54 -0700 Subject: [PATCH] Extract Register On New Group Message Functions --- .../groupmanagement_functionality.go | 24 +++++++++ peer/cwtch_peer.go | 52 ++++++------------- peer/profile_interface.go | 12 +++-- 3 files changed, 49 insertions(+), 39 deletions(-) diff --git a/functionality/groupmanagement/groupmanagement_functionality.go b/functionality/groupmanagement/groupmanagement_functionality.go index a6e4816..e93e250 100644 --- a/functionality/groupmanagement/groupmanagement_functionality.go +++ b/functionality/groupmanagement/groupmanagement_functionality.go @@ -5,6 +5,7 @@ import ( "cwtch.im/cwtch/model/attr" "cwtch.im/cwtch/model/constants" "cwtch.im/cwtch/peer" + "cwtch.im/cwtch/protocol/groups" "encoding/json" "errors" "fmt" @@ -23,6 +24,29 @@ func FunctionalityGate(experimentMap map[string]bool) (*Functionality, error) { return nil, errors.New("groupmanagement is not enabled") } +func (f *Functionality) Init(cp peer.CwtchPeer) { + cp.RegisterOnNewGroupMessage(func(conversationID int, dgm groups.DecryptedGroupMessage, storage *peer.CwtchProfileStorage) { + /// Time to Handle any Meta-Actions + overlayMessage := new(model.MessageWrapper) + err := json.Unmarshal([]byte(dgm.Text), overlayMessage) + if err == nil { + if overlayMessage.Overlay == model.OverlayGroupManagement { + ci, _ := storage.GetConversation(conversationID) + // NOTE: this is safe because dm.Onion will only be valid if there is a valid signature + // from the onion on the message. As such we don't re-verify the signature here. + acl, exists := ci.ACL[dgm.Onion] + if exists && acl.ManageACL { + newACL := new(model.AccessControlList) + err := json.Unmarshal([]byte(overlayMessage.Data), newACL) + if err == nil { + storage.SetConversationACL(conversationID, *newACL) + } + } + } + } + }) +} + // CreateManagedGroup is a convenience function for creating a new managed group func (f *Functionality) CreateManagedGroup(cp peer.CwtchPeer, name string, server string) (int, error) { return cp.StartGroup(name, server) diff --git a/peer/cwtch_peer.go b/peer/cwtch_peer.go index 129a4a2..7826c1f 100644 --- a/peer/cwtch_peer.go +++ b/peer/cwtch_peer.go @@ -68,10 +68,25 @@ type cwtchPeer struct { state map[string]connections.ConnectionState + onNewPeerMessageFunctions []func(conversationID int, message string, storage *CwtchProfileStorage) + onNewGroupMessageFunctions []func(conversationID int, dgm groups.DecryptedGroupMessage, storage *CwtchProfileStorage) + queue event.Queue eventBus event.Manager } +func (cp *cwtchPeer) RegisterOnNewPeerMessage(f func(conversationID int, message string, storage *CwtchProfileStorage)) { + cp.mutex.Lock() + defer cp.mutex.Unlock() + cp.onNewPeerMessageFunctions = append(cp.onNewPeerMessageFunctions, f) +} + +func (cp *cwtchPeer) RegisterOnNewGroupMessage(f func(conversationID int, dgm groups.DecryptedGroupMessage, storage *CwtchProfileStorage)) { + cp.mutex.Lock() + defer cp.mutex.Unlock() + cp.onNewGroupMessageFunctions = append(cp.onNewGroupMessageFunctions, f) +} + func (cp *cwtchPeer) DoStorageTransaction(f func(storage *CwtchProfileStorage) error) error { cp.mutex.Lock() defer cp.mutex.Unlock() @@ -542,24 +557,6 @@ func (cp *cwtchPeer) BlockConversation(id int) error { return cp.storage.SetConversationACL(id, ci.ACL) } -func (cp *cwtchPeer) AddMember(id int, handle string, ac model.AccessControl) error { - cp.mutex.Lock() - defer cp.mutex.Unlock() - ci, err := cp.storage.GetConversation(id) - if err != nil { - return err - } - - requesterHandle, _ := cp.storage.LoadProfileKeyValue(TypeAttribute, attr.PublicScope.ConstructScopedZonedPath(attr.ProfileZone.ConstructZonedPath(constants.Onion)).ToString()) - - if ci.ACL[string(requesterHandle)].ManageACL { - aclCopy := ci.ACL - aclCopy[handle] = ac - cp.storage.SetConversationACL(id, ci.ACL) - } - return fmt.Errorf("unable to add a member to the conversation") -} - // UnblockConversation looks up a conversation by `handle` and sets the Blocked ACL field to `true` // Further actions depend on the Accepted field func (cp *cwtchPeer) UnblockConversation(id int) error { @@ -1356,23 +1353,8 @@ func (cp *cwtchPeer) attemptInsertOrAcknowledgeLegacyGroupConversation(conversat id, err := cp.storage.InsertMessage(conversationID, 0, dm.Text, model.Attributes{constants.AttrAck: constants.True, "PreviousSignature": base64.StdEncoding.EncodeToString(dm.PreviousMessageSig), constants.AttrAuthor: dm.Onion, constants.AttrSentTimestamp: time.Unix(int64(dm.Timestamp), 0).Format(time.RFC3339Nano)}, signature, contenthash) if err == nil { - /// Time to Handle any Meta-Actions - overlayMessage := new(model.MessageWrapper) - err := json.Unmarshal([]byte(dm.Text), overlayMessage) - if err == nil { - if overlayMessage.Overlay == model.OverlayGroupManagement { - ci, _ := cp.storage.GetConversation(conversationID) - // NOTE: this is safe because dm.Onion will only be valid if there is a valid signature - // from the onion on the message. As such we don't re-verify the signature here. - acl, exists := ci.ACL[dm.Onion] - if exists && acl.ManageACL { - newACL := new(model.AccessControlList) - err := json.Unmarshal([]byte(overlayMessage.Data), newACL) - if err == nil { - cp.storage.SetConversationACL(conversationID, *newACL) - } - } - } + for _, f := range cp.onNewGroupMessageFunctions { + f(id, *dm, cp.storage) } cp.eventBus.Publish(event.NewEvent(event.NewMessageFromGroup, map[event.Field]string{event.ConversationID: strconv.Itoa(conversationID), event.TimestampSent: time.Unix(int64(dm.Timestamp), 0).Format(time.RFC3339Nano), event.RemotePeer: dm.Onion, event.Index: strconv.Itoa(id), event.Data: dm.Text, event.ContentHash: contenthash})) diff --git a/peer/profile_interface.go b/peer/profile_interface.go index 459778d..47ec32c 100644 --- a/peer/profile_interface.go +++ b/peer/profile_interface.go @@ -5,6 +5,7 @@ import ( "cwtch.im/cwtch/model" "cwtch.im/cwtch/model/attr" "cwtch.im/cwtch/protocol/connections" + "cwtch.im/cwtch/protocol/groups" "git.openprivacy.ca/openprivacy/connectivity" ) @@ -106,10 +107,6 @@ type CwtchPeer interface { GetConversationAttribute(conversation int, path attr.ScopedZonedPath) (string, error) DeleteConversation(conversation int) error - AddMember(conversation int, handle string, ac model.AccessControl) error - - DoStorageTransaction(func(storage *CwtchProfileStorage) error) error - // New Unified Conversation Channel Interfaces GetChannelMessage(conversation int, channel int, id int) (string, model.Attributes, error) GetChannelMessageCount(conversation int, channel int) (int, error) @@ -122,4 +119,11 @@ type CwtchPeer interface { ChangePassword(oldpassword string, newpassword string, newpasswordAgain string) error Export(file string) error Delete() + + // DoStorageTransaction is a low level API for building new functionality on top of Cwtch Peer + // in general you do not want to use this. + DoStorageTransaction(func(storage *CwtchProfileStorage) error) error + + RegisterOnNewPeerMessage(func(conversationID int, message string, storage *CwtchProfileStorage)) + RegisterOnNewGroupMessage(func(conversationID int, dgm groups.DecryptedGroupMessage, storage *CwtchProfileStorage)) }