94 lines
3.0 KiB
Go
94 lines
3.0 KiB
Go
package groupmanagement
|
|
|
|
import (
|
|
"cwtch.im/cwtch/model"
|
|
"cwtch.im/cwtch/model/attr"
|
|
"cwtch.im/cwtch/model/constants"
|
|
"cwtch.im/cwtch/peer"
|
|
"cwtch.im/cwtch/protocol/groups"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
)
|
|
|
|
// Functionality groups some common UI triggered functions for contacts...
|
|
type Functionality struct {
|
|
}
|
|
|
|
// FunctionalityGate returns groupmanagement if enabled in the given experiment map
|
|
// Note: Experiment maps are currently in libcwtch-go
|
|
func FunctionalityGate(experimentMap map[string]bool) (*Functionality, error) {
|
|
if experimentMap[constants.GroupManagementExperiment] {
|
|
return new(Functionality), nil
|
|
}
|
|
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)
|
|
}
|
|
|
|
// AddNewMember is a convenience function for adding a new member to a group and sending the updated ACL to the group.
|
|
func (f *Functionality) AddNewMember(cp peer.CwtchPeer, id int, handle string, ac model.AccessControl) error {
|
|
|
|
err := cp.DoStorageTransaction(func(storage *peer.CwtchProfileStorage) error {
|
|
ci, err := storage.GetConversation(id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
requesterHandle, _ := storage.LoadProfileKeyValue(peer.TypeAttribute, attr.PublicScope.ConstructScopedZonedPath(attr.ProfileZone.ConstructZonedPath(constants.Onion)).ToString())
|
|
|
|
if ci.ACL[string(requesterHandle)].ManageACL {
|
|
aclCopy := ci.ACL
|
|
aclCopy[handle] = ac
|
|
storage.SetConversationACL(id, ci.ACL)
|
|
}
|
|
return fmt.Errorf("unable to add a member to the conversation")
|
|
})
|
|
|
|
if err == nil {
|
|
return f.syncACL(cp, id)
|
|
}
|
|
return err
|
|
}
|
|
|
|
// syncACL is a convenience function for sending the latest ACL to an existing group.
|
|
func (f *Functionality) syncACL(cp peer.CwtchPeer, id int) error {
|
|
ci, err := cp.GetConversationInfo(id)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
wrapper := model.MessageWrapper{
|
|
Overlay: model.OverlayGroupManagement,
|
|
Data: string(ci.ACL.Serialize()),
|
|
}
|
|
message, _ := json.Marshal(wrapper)
|
|
_, err = cp.SendMessage(id, string(message))
|
|
return err
|
|
}
|