fix logic arroudn accept/block contact and add unblock support
continuous-integration/drone/push Build is passing Details
continuous-integration/drone/pr Build is passing Details

This commit is contained in:
Dan Ballard 2022-01-06 12:55:26 -05:00
parent 42e04c17c3
commit 830e479539
6 changed files with 56 additions and 14 deletions

View File

@ -25,8 +25,10 @@ const (
RetryServerRequest = Type("RetryServerRequest") RetryServerRequest = Type("RetryServerRequest")
// RemotePeer // RemotePeer
// Authorization(model.peer.Auth_...) // ConversationID
SetPeerAuthorization = Type("UpdatePeerAuthorization") // Accepted
// Blocked
UpdateConversationAuthorization = Type("UpdateConversationAuthorization")
// Turn on/off blocking of unknown peers (if peers aren't in the contact list then they will be autoblocked // Turn on/off blocking of unknown peers (if peers aren't in the contact list then they will be autoblocked
BlockUnknownPeers = Type("BlockUnknownPeers") BlockUnknownPeers = Type("BlockUnknownPeers")
@ -263,7 +265,8 @@ const (
// Flags denotes a set of message flags // Flags denotes a set of message flags
Flags = Field("Flags") Flags = Field("Flags")
Authorization = Field("Authorization") Accepted = Field("Accepted")
Blocked = Field("Blocked")
KeyBundle = Field("KeyBundle") KeyBundle = Field("KeyBundle")

View File

@ -13,6 +13,12 @@ type AccessControl struct {
Append bool // Allows a handle to append new messages to the conversation Append bool // Allows a handle to append new messages to the conversation
} }
// Serialize transforms the AccessControl into json.
func (ac *AccessControl) Serialize() []byte {
data, _ := json.Marshal(ac)
return data
}
// DefaultP2PAccessControl - because in the year 2021, go does not support constant structs... // DefaultP2PAccessControl - because in the year 2021, go does not support constant structs...
func DefaultP2PAccessControl() AccessControl { func DefaultP2PAccessControl() AccessControl {
return AccessControl{Read: true, Append: true, Blocked: false} return AccessControl{Read: true, Append: true, Blocked: false}

View File

@ -486,33 +486,58 @@ func (cp *cwtchPeer) AcceptConversation(id int) error {
err := cp.storage.AcceptConversation(id) err := cp.storage.AcceptConversation(id)
if err == nil { if err == nil {
// If a p2p conversation then attempt to peer with the onion... // If a p2p conversation then attempt to peer with the onion...
// Groups and Server have their own acceptance flow. // Groups and Server have their own acceptance flow.,
ci, _ := cp.storage.GetConversation(id) ci, err := cp.storage.GetConversation(id)
if err != nil {
log.Errorf("Could not get conversation for %v: %v", id, err)
return err
}
if !ci.IsGroup() && !ci.IsServer() { if !ci.IsGroup() && !ci.IsServer() {
cp.eventBus.Publish(event.NewEvent(event.SetPeerAuthorization, map[event.Field]string{event.ConversationID: strconv.Itoa(id), event.RemotePeer: ci.Handle, event.Authorization: string(model.AuthApproved)})) cp.sendUpdateAuth(id, ci.Handle, ci.Accepted, ci.ACL[ci.Handle].Blocked)
cp.PeerWithOnion(ci.Handle) cp.PeerWithOnion(ci.Handle)
} }
} }
return err return err
} }
// BlockConversation looks up a conversation by `handle` and sets the Accepted status to `true` // BlockConversation looks up a conversation by `handle` and sets the Blocked ACL field to `true`
// This will cause Cwtch to auto connect to this conversation on start up // This will cause Cwtch to never try to connect to and refuse connections from the peer
func (cp *cwtchPeer) BlockConversation(id int) error { func (cp *cwtchPeer) BlockConversation(id int) error {
return cp.setACL(id, &model.AccessControl{Blocked: true, Read: false, Append: false})
}
// 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 {
return cp.setACL(id, &model.AccessControl{Blocked: false, Read: false, Append: false})
}
func (cp *cwtchPeer) setACL(id int, acl *model.AccessControl) error {
cp.mutex.Lock() cp.mutex.Lock()
defer cp.mutex.Unlock() defer cp.mutex.Unlock()
ci, err := cp.storage.GetConversation(id) ci, err := cp.storage.GetConversation(id)
if err != nil { if err != nil {
return err return err
} }
// p2p conversations have a single ACL referencing the remote peer. Set this to blocked... // p2p conversations have a single ACL referencing the remote peer. Set this to blocked...
ci.ACL[ci.Handle] = model.AccessControl{Blocked: true, Read: false, Append: false} ci.ACL[ci.Handle] = *acl
// Send an event in any case to block the protocol engine... // Send an event in any case to block the protocol engine...
// TODO at some point in the future engine needs to understand ACLs not just legacy auth status // TODO at some point in the future engine needs to understand ACLs not just legacy auth status
cp.eventBus.Publish(event.NewEvent(event.SetPeerAuthorization, map[event.Field]string{event.ConversationID: strconv.Itoa(id), event.RemotePeer: ci.Handle, event.Authorization: string(model.AuthBlocked)})) cp.sendUpdateAuth(id, ci.Handle, ci.Accepted, ci.ACL[ci.Handle].Blocked)
if !ci.IsGroup() && !ci.IsServer() && ci.Accepted {
cp.PeerWithOnion(ci.Handle)
}
return cp.storage.SetConversationACL(id, ci.ACL) return cp.storage.SetConversationACL(id, ci.ACL)
} }
func (cp *cwtchPeer) sendUpdateAuth(id int, handle string, accepted bool, blocked bool) {
cp.eventBus.Publish(event.NewEvent(event.UpdateConversationAuthorization, map[event.Field]string{event.ConversationID: strconv.Itoa(id), event.RemotePeer: handle, event.Accepted: strconv.FormatBool(accepted), event.Blocked: strconv.FormatBool(blocked)}))
}
func (cp *cwtchPeer) FetchConversations() ([]*model.Conversation, error) { func (cp *cwtchPeer) FetchConversations() ([]*model.Conversation, error) {
cp.mutex.Lock() cp.mutex.Lock()
defer cp.mutex.Unlock() defer cp.mutex.Unlock()

View File

@ -393,7 +393,7 @@ func (cps *CwtchProfileStorage) DeleteConversation(id int) error {
// SetConversationACL sets a new ACL on a given conversation. // SetConversationACL sets a new ACL on a given conversation.
func (cps *CwtchProfileStorage) SetConversationACL(id int, acl model.AccessControlList) error { func (cps *CwtchProfileStorage) SetConversationACL(id int, acl model.AccessControlList) error {
_, err := cps.setConversationACLStmt.Exec(acl, id) _, err := cps.setConversationACLStmt.Exec(acl.Serialize(), id)
if err != nil { if err != nil {
log.Errorf("error executing query: %v", err) log.Errorf("error executing query: %v", err)
return err return err

View File

@ -101,6 +101,7 @@ type CwtchPeer interface {
FetchConversationInfo(handle string) (*model.Conversation, error) FetchConversationInfo(handle string) (*model.Conversation, error)
AcceptConversation(conversation int) error AcceptConversation(conversation int) error
BlockConversation(conversation int) error BlockConversation(conversation int) error
UnblockConversation(conversation int) error
SetConversationAttribute(conversation int, path attr.ScopedZonedPath, value string) error SetConversationAttribute(conversation int, path attr.ScopedZonedPath, value string) error
GetConversationAttribute(conversation int, path attr.ScopedZonedPath) (string, error) GetConversationAttribute(conversation int, path attr.ScopedZonedPath) (string, error)
DeleteConversation(conversation int) error DeleteConversation(conversation int) error

View File

@ -103,7 +103,7 @@ func NewProtocolEngine(identity primitives.Identity, privateKey ed25519.PrivateK
engine.eventManager.Subscribe(event.DeleteContact, engine.queue) engine.eventManager.Subscribe(event.DeleteContact, engine.queue)
engine.eventManager.Subscribe(event.DeleteGroup, engine.queue) engine.eventManager.Subscribe(event.DeleteGroup, engine.queue)
engine.eventManager.Subscribe(event.SetPeerAuthorization, engine.queue) engine.eventManager.Subscribe(event.UpdateConversationAuthorization, engine.queue)
engine.eventManager.Subscribe(event.BlockUnknownPeers, engine.queue) engine.eventManager.Subscribe(event.BlockUnknownPeers, engine.queue)
engine.eventManager.Subscribe(event.AllowUnknownPeers, engine.queue) engine.eventManager.Subscribe(event.AllowUnknownPeers, engine.queue)
@ -186,8 +186,15 @@ func (e *engine) eventHandler() {
if err := e.sendRetValToPeer(ev.EventID, ev.Data[event.RemotePeer], ev.Data[event.Data], ev.Data[event.Exists]); err != nil { if err := e.sendRetValToPeer(ev.EventID, ev.Data[event.RemotePeer], ev.Data[event.Data], ev.Data[event.Exists]); err != nil {
e.eventManager.Publish(event.NewEvent(event.SendMessageToPeerError, map[event.Field]string{event.EventContext: string(event.SendRetValMessageToPeer), event.RemotePeer: ev.Data[event.RemotePeer], event.EventID: ev.EventID, event.Error: err.Error()})) e.eventManager.Publish(event.NewEvent(event.SendMessageToPeerError, map[event.Field]string{event.EventContext: string(event.SendRetValMessageToPeer), event.RemotePeer: ev.Data[event.RemotePeer], event.EventID: ev.EventID, event.Error: err.Error()}))
} }
case event.SetPeerAuthorization: case event.UpdateConversationAuthorization:
auth := model.Authorization(ev.Data[event.Authorization]) accepted, _ := strconv.ParseBool(ev.Data[event.Accepted])
blocked, _ := strconv.ParseBool(ev.Data[event.Blocked])
auth := model.AuthUnknown
if blocked {
auth = model.AuthBlocked
} else if accepted {
auth = model.AuthApproved
}
e.authorizations.Store(ev.Data[event.RemotePeer], auth) e.authorizations.Store(ev.Data[event.RemotePeer], auth)
if auth == model.AuthBlocked { if auth == model.AuthBlocked {
connection, err := e.service.GetConnection(ev.Data[event.RemotePeer]) connection, err := e.service.GetConnection(ev.Data[event.RemotePeer])