2018-03-11 18:49:10 +00:00
|
|
|
package peer
|
2018-03-09 20:44:13 +00:00
|
|
|
|
|
|
|
import (
|
2019-01-04 21:44:21 +00:00
|
|
|
"cwtch.im/cwtch/event"
|
2018-05-28 18:05:06 +00:00
|
|
|
"cwtch.im/cwtch/model"
|
2020-03-07 07:41:00 +00:00
|
|
|
"cwtch.im/cwtch/model/attr"
|
2019-01-04 21:44:21 +00:00
|
|
|
"cwtch.im/cwtch/protocol/connections"
|
2019-05-15 20:12:11 +00:00
|
|
|
"encoding/base32"
|
2018-06-09 07:49:18 +00:00
|
|
|
"encoding/base64"
|
2019-02-03 01:18:33 +00:00
|
|
|
"encoding/json"
|
2018-03-30 21:16:51 +00:00
|
|
|
"errors"
|
2020-02-10 22:09:24 +00:00
|
|
|
"git.openprivacy.ca/openprivacy/log"
|
2020-03-07 07:41:00 +00:00
|
|
|
"strconv"
|
2018-06-09 07:49:18 +00:00
|
|
|
"strings"
|
2018-03-09 20:44:13 +00:00
|
|
|
"sync"
|
2019-01-22 19:11:25 +00:00
|
|
|
"time"
|
2018-03-09 20:44:13 +00:00
|
|
|
)
|
|
|
|
|
2019-10-18 23:56:10 +00:00
|
|
|
var autoHandleableEvents = map[event.Type]bool{event.EncryptedGroupMessage: true, event.PeerStateChange: true,
|
|
|
|
event.ServerStateChange: true, event.NewGroupInvite: true, event.NewMessageFromPeer: true,
|
2020-03-07 07:41:00 +00:00
|
|
|
event.PeerAcknowledgement: true, event.PeerError: true, event.SendMessageToGroupError: true,
|
2021-04-28 19:47:55 +00:00
|
|
|
event.NewGetValMessageFromPeer: true, event.NewRetValMessageFromPeer: true, event.ProtocolEngineStopped: true, event.RetryServerRequest: true}
|
2019-09-19 23:14:35 +00:00
|
|
|
|
2020-10-22 23:21:33 +00:00
|
|
|
// DefaultEventsToHandle specifies which events will be subscribed to
|
|
|
|
// when a peer has its Init() function called
|
2020-10-03 22:13:06 +00:00
|
|
|
var DefaultEventsToHandle = []event.Type{
|
|
|
|
event.EncryptedGroupMessage,
|
|
|
|
event.NewMessageFromPeer,
|
|
|
|
event.PeerAcknowledgement,
|
|
|
|
event.NewGroupInvite,
|
|
|
|
event.PeerError,
|
|
|
|
event.SendMessageToGroupError,
|
|
|
|
event.NewGetValMessageFromPeer,
|
2021-04-13 22:12:12 +00:00
|
|
|
event.ProtocolEngineStopped,
|
2021-04-28 19:47:55 +00:00
|
|
|
event.RetryServerRequest,
|
2020-10-03 22:13:06 +00:00
|
|
|
}
|
|
|
|
|
2018-10-06 03:50:55 +00:00
|
|
|
// cwtchPeer manages incoming and outgoing connections and all processing for a Cwtch cwtchPeer
|
2018-06-19 22:28:44 +00:00
|
|
|
type cwtchPeer struct {
|
2021-04-13 22:12:12 +00:00
|
|
|
Profile *model.Profile
|
|
|
|
mutex sync.Mutex
|
|
|
|
shutdown bool
|
|
|
|
listenStatus bool
|
2019-01-04 21:44:21 +00:00
|
|
|
|
2019-08-14 20:56:45 +00:00
|
|
|
queue event.Queue
|
2019-06-05 20:40:55 +00:00
|
|
|
eventBus event.Manager
|
2018-03-09 20:44:13 +00:00
|
|
|
}
|
|
|
|
|
2021-04-06 21:22:36 +00:00
|
|
|
// BlockUnknownConnections will auto disconnect from connections if authentication doesn't resolve a hostname
|
|
|
|
// known to peer.
|
|
|
|
func (cp *cwtchPeer) BlockUnknownConnections() {
|
|
|
|
cp.eventBus.Publish(event.NewEvent(event.BlockUnknownPeers, map[event.Field]string{}))
|
|
|
|
}
|
|
|
|
|
|
|
|
// AllowUnknownConnections will permit connections from unknown contacts.
|
|
|
|
func (cp *cwtchPeer) AllowUnknownConnections() {
|
|
|
|
cp.eventBus.Publish(event.NewEvent(event.AllowUnknownPeers, map[event.Field]string{}))
|
|
|
|
}
|
|
|
|
|
2021-03-29 18:53:02 +00:00
|
|
|
// ReadContacts is a meta-interface intended to restrict callers to read-only access to contacts
|
|
|
|
type ReadContacts interface {
|
|
|
|
GetContacts() []string
|
|
|
|
GetContact(string) *model.PublicProfile
|
|
|
|
GetContactAttribute(string, string) (string, bool)
|
|
|
|
}
|
2018-06-19 22:28:44 +00:00
|
|
|
|
2021-03-29 18:53:02 +00:00
|
|
|
// ModifyContacts is a meta-interface intended to restrict callers to modify-only access to contacts
|
|
|
|
type ModifyContacts interface {
|
|
|
|
AddContact(nick, onion string, authorization model.Authorization)
|
2020-06-16 00:16:04 +00:00
|
|
|
SetContactAuthorization(string, model.Authorization) error
|
2021-03-29 18:53:02 +00:00
|
|
|
SetContactAttribute(string, string, string)
|
2019-08-07 05:27:11 +00:00
|
|
|
DeleteContact(string)
|
2021-03-29 18:53:02 +00:00
|
|
|
}
|
2020-02-03 18:46:15 +00:00
|
|
|
|
2021-03-29 18:53:02 +00:00
|
|
|
// AccessPeeringState provides access to functions relating to the underlying connections of a peer.
|
|
|
|
type AccessPeeringState interface {
|
2020-02-03 18:46:15 +00:00
|
|
|
GetPeerState(string) (connections.ConnectionState, bool)
|
2021-03-29 18:53:02 +00:00
|
|
|
}
|
2018-06-19 22:28:44 +00:00
|
|
|
|
2021-03-29 18:53:02 +00:00
|
|
|
// ModifyPeeringState is a meta-interface intended to restrict callers to modify-only access to connection peers
|
|
|
|
type ModifyPeeringState interface {
|
2021-04-06 21:22:36 +00:00
|
|
|
BlockUnknownConnections()
|
|
|
|
AllowUnknownConnections()
|
2021-03-29 18:53:02 +00:00
|
|
|
PeerWithOnion(string)
|
|
|
|
JoinServer(string) error
|
|
|
|
}
|
2018-06-19 22:28:44 +00:00
|
|
|
|
2021-03-29 18:53:02 +00:00
|
|
|
// ModifyContactsAndPeers is a meta-interface intended to restrict a call to reading and modifying contacts
|
|
|
|
// and peers.
|
|
|
|
type ModifyContactsAndPeers interface {
|
|
|
|
ReadContacts
|
|
|
|
ModifyContacts
|
|
|
|
ModifyPeeringState
|
|
|
|
}
|
|
|
|
|
|
|
|
// ReadServers provides access to the servers
|
|
|
|
type ReadServers interface {
|
|
|
|
GetServers() []string
|
|
|
|
}
|
2018-06-19 22:28:44 +00:00
|
|
|
|
2021-03-29 18:53:02 +00:00
|
|
|
// ReadGroups provides read-only access to group state
|
|
|
|
type ReadGroups interface {
|
2018-06-19 22:28:44 +00:00
|
|
|
GetGroup(string) *model.Group
|
2020-02-03 18:46:15 +00:00
|
|
|
GetGroupState(string) (connections.ConnectionState, bool)
|
2018-06-19 22:28:44 +00:00
|
|
|
GetGroups() []string
|
2021-03-29 18:53:02 +00:00
|
|
|
GetGroupAttribute(string, string) (string, bool)
|
|
|
|
ExportGroup(string) (string, error)
|
|
|
|
}
|
2018-06-19 22:28:44 +00:00
|
|
|
|
2021-03-29 18:53:02 +00:00
|
|
|
// ModifyGroups provides write-only access add/edit/remove new groups
|
|
|
|
type ModifyGroups interface {
|
2021-05-03 23:32:48 +00:00
|
|
|
ImportGroup(string) (string, error)
|
|
|
|
StartGroup(string) (string, string, error)
|
2021-03-29 18:53:02 +00:00
|
|
|
AcceptInvite(string) error
|
|
|
|
RejectInvite(string)
|
|
|
|
DeleteGroup(string)
|
2019-10-31 21:39:31 +00:00
|
|
|
SetGroupAttribute(string, string, string)
|
2021-03-29 18:53:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ModifyServers provides write-only access to servers
|
|
|
|
type ModifyServers interface {
|
|
|
|
AddServer(string) error
|
|
|
|
}
|
|
|
|
|
|
|
|
// SendMessages enables a caller to sender messages to a contact
|
|
|
|
// Note:
|
|
|
|
type SendMessages interface {
|
|
|
|
SendGetValToPeer(string, string, string)
|
|
|
|
SendMessageToPeer(string, string) string
|
|
|
|
|
|
|
|
// TODO This should probably not be exposed
|
|
|
|
StoreMessage(onion string, messageTxt string, sent time.Time)
|
|
|
|
|
|
|
|
// TODO Extract once groups are stable
|
|
|
|
InviteOnionToGroup(string, string) error
|
|
|
|
}
|
2019-10-31 21:39:31 +00:00
|
|
|
|
2021-03-29 18:53:02 +00:00
|
|
|
// SendMessagesToGroup enables a caller to sender messages to a group
|
|
|
|
type SendMessagesToGroup interface {
|
|
|
|
SendMessageToGroupTracked(string, string) (string, error)
|
|
|
|
}
|
|
|
|
|
|
|
|
// CwtchPeer provides us with a way of testing systems built on top of cwtch without having to
|
|
|
|
// directly implement a cwtchPeer.
|
|
|
|
type CwtchPeer interface {
|
|
|
|
|
|
|
|
// Core Cwtch Peer Functions that should not be exposed to
|
|
|
|
// most functions
|
|
|
|
Init(event.Manager)
|
|
|
|
AutoHandleEvents(events []event.Type)
|
2018-11-10 22:14:12 +00:00
|
|
|
Listen()
|
2019-05-15 20:12:11 +00:00
|
|
|
StartPeersConnections()
|
2020-10-29 21:22:33 +00:00
|
|
|
StartServerConnections()
|
2018-06-19 22:28:44 +00:00
|
|
|
Shutdown()
|
2021-03-29 18:53:02 +00:00
|
|
|
|
|
|
|
// Relating to local attributes
|
|
|
|
GetOnion() string
|
|
|
|
SetAttribute(string, string)
|
|
|
|
GetAttribute(string) (string, bool)
|
|
|
|
|
|
|
|
ReadContacts
|
|
|
|
ModifyContacts
|
|
|
|
|
|
|
|
AccessPeeringState
|
|
|
|
ModifyPeeringState
|
|
|
|
|
|
|
|
ReadGroups
|
|
|
|
ModifyGroups
|
|
|
|
|
|
|
|
ReadServers
|
|
|
|
ModifyServers
|
|
|
|
|
|
|
|
SendMessages
|
|
|
|
SendMessagesToGroup
|
2018-06-19 22:28:44 +00:00
|
|
|
}
|
|
|
|
|
2018-06-24 18:59:42 +00:00
|
|
|
// NewCwtchPeer creates and returns a new cwtchPeer with the given name.
|
2018-10-06 03:50:55 +00:00
|
|
|
func NewCwtchPeer(name string) CwtchPeer {
|
2018-06-23 23:56:51 +00:00
|
|
|
cp := new(cwtchPeer)
|
2018-05-01 20:44:45 +00:00
|
|
|
cp.Profile = model.GenerateNewProfile(name)
|
2018-11-10 22:14:12 +00:00
|
|
|
cp.shutdown = false
|
2018-10-06 03:50:55 +00:00
|
|
|
return cp
|
2018-10-15 00:59:53 +00:00
|
|
|
}
|
|
|
|
|
2018-10-06 03:50:55 +00:00
|
|
|
// FromProfile generates a new peer from a profile.
|
|
|
|
func FromProfile(profile *model.Profile) CwtchPeer {
|
|
|
|
cp := new(cwtchPeer)
|
|
|
|
cp.Profile = profile
|
2019-09-19 23:14:35 +00:00
|
|
|
cp.shutdown = false
|
2018-10-06 03:50:55 +00:00
|
|
|
return cp
|
2018-03-09 20:44:13 +00:00
|
|
|
}
|
|
|
|
|
2018-10-06 03:50:55 +00:00
|
|
|
// Init instantiates a cwtchPeer
|
2019-06-21 21:50:43 +00:00
|
|
|
func (cp *cwtchPeer) Init(eventBus event.Manager) {
|
2020-10-03 22:13:06 +00:00
|
|
|
cp.InitForEvents(eventBus, DefaultEventsToHandle)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cp *cwtchPeer) InitForEvents(eventBus event.Manager, toBeHandled []event.Type) {
|
2019-08-14 20:56:45 +00:00
|
|
|
cp.queue = event.NewQueue()
|
2019-01-04 21:44:21 +00:00
|
|
|
go cp.eventHandler()
|
|
|
|
|
|
|
|
cp.eventBus = eventBus
|
2020-10-03 22:13:06 +00:00
|
|
|
cp.AutoHandleEvents(toBeHandled)
|
2019-09-19 23:14:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// AutoHandleEvents sets an event (if able) to be handled by this peer
|
|
|
|
func (cp *cwtchPeer) AutoHandleEvents(events []event.Type) {
|
|
|
|
for _, ev := range events {
|
|
|
|
if _, exists := autoHandleableEvents[ev]; exists {
|
|
|
|
cp.eventBus.Subscribe(ev, cp.queue)
|
|
|
|
} else {
|
|
|
|
log.Errorf("Peer asked to autohandle event it cannot: %v\n", ev)
|
|
|
|
}
|
|
|
|
}
|
2018-03-09 20:44:13 +00:00
|
|
|
}
|
|
|
|
|
2021-04-28 19:47:55 +00:00
|
|
|
// ImportGroup initializes a group from an imported source rather than a peer invite
|
2021-05-03 23:32:48 +00:00
|
|
|
func (cp *cwtchPeer) ImportGroup(exportedInvite string) (string, error) {
|
|
|
|
cp.mutex.Lock()
|
|
|
|
defer cp.mutex.Unlock()
|
|
|
|
gid, err := cp.Profile.ProcessInvite(exportedInvite)
|
|
|
|
|
|
|
|
if err == nil {
|
|
|
|
cp.eventBus.Publish(event.NewEvent(event.NewGroup, map[event.Field]string{event.GroupID: gid, event.GroupInvite: exportedInvite}))
|
2018-06-09 07:49:18 +00:00
|
|
|
}
|
2021-05-03 23:32:48 +00:00
|
|
|
|
|
|
|
return gid, err
|
2018-06-09 07:49:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ExportGroup serializes a group invite so it can be given offline
|
2018-06-19 22:28:44 +00:00
|
|
|
func (cp *cwtchPeer) ExportGroup(groupID string) (string, error) {
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Lock()
|
|
|
|
defer cp.mutex.Unlock()
|
2019-10-31 21:39:31 +00:00
|
|
|
group := cp.Profile.GetGroup(groupID)
|
2018-06-09 07:49:18 +00:00
|
|
|
if group != nil {
|
2021-05-03 23:32:48 +00:00
|
|
|
return group.Invite()
|
2018-06-09 07:49:18 +00:00
|
|
|
}
|
|
|
|
return "", errors.New("group id could not be found")
|
|
|
|
}
|
|
|
|
|
2018-06-19 22:28:44 +00:00
|
|
|
// StartGroup create a new group linked to the given server and returns the group ID, an invite or an error.
|
2021-05-03 23:32:48 +00:00
|
|
|
func (cp *cwtchPeer) StartGroup(server string) (string, string, error) {
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Lock()
|
2021-05-03 23:32:48 +00:00
|
|
|
groupID, invite, err := cp.Profile.StartGroup(server)
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Unlock()
|
2019-02-03 01:18:33 +00:00
|
|
|
if err == nil {
|
|
|
|
group := cp.GetGroup(groupID)
|
|
|
|
jsobj, err := json.Marshal(group)
|
2019-02-03 03:24:42 +00:00
|
|
|
if err == nil {
|
2019-02-03 01:18:33 +00:00
|
|
|
cp.eventBus.Publish(event.NewEvent(event.GroupCreated, map[event.Field]string{
|
|
|
|
event.Data: string(jsobj),
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
log.Errorf("error creating group: %v", err)
|
|
|
|
}
|
2021-05-03 23:32:48 +00:00
|
|
|
return groupID, invite, err
|
2018-09-21 18:02:46 +00:00
|
|
|
}
|
|
|
|
|
2018-06-19 22:28:44 +00:00
|
|
|
// GetGroups returns an unordered list of all group IDs.
|
|
|
|
func (cp *cwtchPeer) GetGroups() []string {
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Lock()
|
|
|
|
defer cp.mutex.Unlock()
|
2018-06-19 22:28:44 +00:00
|
|
|
return cp.Profile.GetGroups()
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetGroup returns a pointer to a specific group, nil if no group exists.
|
|
|
|
func (cp *cwtchPeer) GetGroup(groupID string) *model.Group {
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Lock()
|
|
|
|
defer cp.mutex.Unlock()
|
2019-10-31 21:39:31 +00:00
|
|
|
return cp.Profile.GetGroup(groupID)
|
2018-06-19 22:28:44 +00:00
|
|
|
}
|
|
|
|
|
2020-06-16 00:16:04 +00:00
|
|
|
func (cp *cwtchPeer) AddContact(nick, onion string, authorization model.Authorization) {
|
2019-05-15 20:12:11 +00:00
|
|
|
decodedPub, _ := base32.StdEncoding.DecodeString(strings.ToUpper(onion))
|
2020-06-16 00:16:04 +00:00
|
|
|
pp := &model.PublicProfile{Name: nick, Ed25519PublicKey: decodedPub, Authorization: authorization, Onion: onion, Attributes: map[string]string{"nick": nick}}
|
2019-02-03 01:18:33 +00:00
|
|
|
cp.Profile.AddContact(onion, pp)
|
2019-02-04 19:39:58 +00:00
|
|
|
pd, _ := json.Marshal(pp)
|
2019-02-03 01:18:33 +00:00
|
|
|
cp.eventBus.Publish(event.NewEvent(event.PeerCreated, map[event.Field]string{
|
2019-02-04 19:39:58 +00:00
|
|
|
event.Data: string(pd),
|
2019-02-03 01:18:33 +00:00
|
|
|
event.RemotePeer: onion,
|
|
|
|
}))
|
2020-06-16 00:16:04 +00:00
|
|
|
cp.eventBus.Publish(event.NewEventList(event.SetPeerAuthorization, event.RemotePeer, onion, event.Authorization, string(authorization)))
|
2020-07-08 18:29:33 +00:00
|
|
|
|
|
|
|
// Default to Deleting Peer History
|
|
|
|
cp.eventBus.Publish(event.NewEventList(event.SetPeerAttribute, event.RemotePeer, onion, event.SaveHistoryKey, event.DeleteHistoryDefault))
|
2019-02-03 01:18:33 +00:00
|
|
|
}
|
|
|
|
|
2020-07-23 21:40:44 +00:00
|
|
|
// AddServer takes in a serialized server specification (a bundle of related keys) and adds a contact for the
|
|
|
|
// server assuming there are no errors and the contact doesn't already exist.
|
|
|
|
// TODO in the future this function should also integrate with a trust provider to validate the key bundle.
|
2020-07-22 17:14:32 +00:00
|
|
|
func (cp *cwtchPeer) AddServer(serverSpecification string) error {
|
2020-10-01 17:13:45 +00:00
|
|
|
// This confirms that the server did at least sign the bundle
|
|
|
|
keyBundle, err := model.DeserializeAndVerify([]byte(serverSpecification))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2021-05-07 00:15:01 +00:00
|
|
|
log.Debugf("Got new key bundle %v", keyBundle.Serialize())
|
|
|
|
|
|
|
|
// TODO if the key bundle is incomplete then error out. In the future we may allow servers to attest to new
|
|
|
|
// keys or subsets of keys, but for now they must commit only to a complete set of keys required for Cwtch Groups
|
|
|
|
// (that way we can be assured that the keybundle we store is a valid one)
|
|
|
|
if keyBundle.HasKeyType(model.KeyTypeTokenOnion) == false || keyBundle.HasKeyType(model.KeyTypeServerOnion) == false || keyBundle.HasKeyType(model.KeyTypePrivacyPass) == false {
|
|
|
|
return errors.New("keybundle is incomplete")
|
|
|
|
}
|
|
|
|
|
2020-07-22 17:14:32 +00:00
|
|
|
if keyBundle.HasKeyType(model.KeyTypeServerOnion) {
|
|
|
|
onionKey, _ := keyBundle.GetKey(model.KeyTypeServerOnion)
|
2020-07-14 00:46:05 +00:00
|
|
|
onion := string(onionKey)
|
|
|
|
|
2021-05-07 00:15:01 +00:00
|
|
|
// Add the contact if we don't already have it
|
2020-07-22 17:14:32 +00:00
|
|
|
if cp.GetContact(onion) == nil {
|
|
|
|
decodedPub, _ := base32.StdEncoding.DecodeString(strings.ToUpper(onion))
|
|
|
|
ab := keyBundle.AttributeBundle()
|
|
|
|
pp := &model.PublicProfile{Name: onion, Ed25519PublicKey: decodedPub, Authorization: model.AuthUnknown, Onion: onion, Attributes: ab}
|
|
|
|
|
2021-05-07 00:15:01 +00:00
|
|
|
// The only part of this function that actually modifies the profile...
|
|
|
|
cp.mutex.Lock()
|
2020-07-22 17:14:32 +00:00
|
|
|
cp.Profile.AddContact(onion, pp)
|
2021-05-07 00:15:01 +00:00
|
|
|
cp.mutex.Unlock()
|
|
|
|
|
2020-07-22 17:14:32 +00:00
|
|
|
pd, _ := json.Marshal(pp)
|
|
|
|
cp.eventBus.Publish(event.NewEvent(event.PeerCreated, map[event.Field]string{
|
|
|
|
event.Data: string(pd),
|
|
|
|
event.RemotePeer: onion,
|
|
|
|
}))
|
|
|
|
}
|
2020-10-01 17:13:45 +00:00
|
|
|
|
2021-05-07 00:15:01 +00:00
|
|
|
// At this point we know the server exists
|
2020-10-01 17:13:45 +00:00
|
|
|
server := cp.GetContact(onion)
|
|
|
|
ab := keyBundle.AttributeBundle()
|
|
|
|
|
2021-05-07 00:15:01 +00:00
|
|
|
// Check server bundle for consistency if we have different keys stored than in the tofu bundle then we
|
|
|
|
// abort...
|
2020-10-01 17:13:45 +00:00
|
|
|
for k, v := range ab {
|
|
|
|
val, exists := server.GetAttribute(k)
|
|
|
|
if exists {
|
|
|
|
if val != v {
|
|
|
|
// this is inconsistent!
|
|
|
|
return model.InconsistentKeyBundleError
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// we haven't seen this key associated with the server before
|
|
|
|
}
|
|
|
|
|
2021-05-07 00:15:01 +00:00
|
|
|
// Store the key bundle for the server so we can reconstruct a tofubundle invite
|
2021-05-07 01:14:22 +00:00
|
|
|
cp.SetContactAttribute(onion, string(model.BundleType), serverSpecification)
|
2021-05-07 00:15:01 +00:00
|
|
|
|
2020-10-01 17:13:45 +00:00
|
|
|
// If we have gotten to this point we can assume this is a safe key bundle signed by the
|
|
|
|
// server with no conflicting keys. So we are going to publish all the keys
|
|
|
|
for k, v := range ab {
|
|
|
|
log.Debugf("Server (%v) has %v key %v", onion, k, v)
|
2021-05-07 01:14:22 +00:00
|
|
|
cp.SetContactAttribute(onion, k, v)
|
2020-10-01 17:13:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
2020-07-14 00:46:05 +00:00
|
|
|
}
|
2020-07-22 17:14:32 +00:00
|
|
|
return err
|
2020-07-14 00:46:05 +00:00
|
|
|
}
|
|
|
|
|
2018-06-19 22:28:44 +00:00
|
|
|
// GetContacts returns an unordered list of onions
|
|
|
|
func (cp *cwtchPeer) GetContacts() []string {
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Lock()
|
|
|
|
defer cp.mutex.Unlock()
|
2018-06-19 22:28:44 +00:00
|
|
|
return cp.Profile.GetContacts()
|
|
|
|
}
|
|
|
|
|
2020-12-17 01:40:03 +00:00
|
|
|
// GetServers returns an unordered list of servers
|
|
|
|
func (cp *cwtchPeer) GetServers() []string {
|
|
|
|
contacts := cp.Profile.GetContacts()
|
|
|
|
var servers []string
|
|
|
|
for _, contact := range contacts {
|
|
|
|
if cp.GetContact(contact).IsServer() {
|
|
|
|
servers = append(servers, contact)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return servers
|
|
|
|
}
|
|
|
|
|
2018-06-19 22:28:44 +00:00
|
|
|
// GetContact returns a given contact, nil is no such contact exists
|
|
|
|
func (cp *cwtchPeer) GetContact(onion string) *model.PublicProfile {
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Lock()
|
|
|
|
defer cp.mutex.Unlock()
|
2018-06-19 22:28:44 +00:00
|
|
|
contact, _ := cp.Profile.GetContact(onion)
|
|
|
|
return contact
|
|
|
|
}
|
|
|
|
|
2020-02-03 18:46:15 +00:00
|
|
|
func (cp *cwtchPeer) GetOnion() string {
|
|
|
|
cp.mutex.Lock()
|
|
|
|
defer cp.mutex.Unlock()
|
|
|
|
return cp.Profile.Onion
|
|
|
|
}
|
|
|
|
func (cp *cwtchPeer) GetPeerState(onion string) (connections.ConnectionState, bool) {
|
|
|
|
cp.mutex.Lock()
|
|
|
|
defer cp.mutex.Unlock()
|
|
|
|
if peer, ok := cp.Profile.Contacts[onion]; ok {
|
2021-03-19 21:20:22 +00:00
|
|
|
return connections.ConnectionStateToType()[peer.State], true
|
2020-02-03 18:46:15 +00:00
|
|
|
}
|
|
|
|
return connections.DISCONNECTED, false
|
2019-05-15 20:12:11 +00:00
|
|
|
}
|
|
|
|
|
2020-02-03 18:46:15 +00:00
|
|
|
func (cp *cwtchPeer) GetGroupState(groupid string) (connections.ConnectionState, bool) {
|
|
|
|
cp.mutex.Lock()
|
|
|
|
defer cp.mutex.Unlock()
|
|
|
|
if group, ok := cp.Profile.Groups[groupid]; ok {
|
2021-03-19 21:20:22 +00:00
|
|
|
return connections.ConnectionStateToType()[group.State], true
|
2020-02-03 18:46:15 +00:00
|
|
|
}
|
|
|
|
return connections.DISCONNECTED, false
|
2019-05-15 20:12:11 +00:00
|
|
|
}
|
|
|
|
|
2018-06-19 22:28:44 +00:00
|
|
|
// PeerWithOnion is the entry point for cwtchPeer relationships
|
2019-07-17 19:10:52 +00:00
|
|
|
func (cp *cwtchPeer) PeerWithOnion(onion string) {
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Lock()
|
2020-06-16 00:16:04 +00:00
|
|
|
defer cp.mutex.Unlock()
|
2020-09-21 22:39:15 +00:00
|
|
|
if _, exists := cp.Profile.GetContact(onion); !exists {
|
2020-06-16 00:16:04 +00:00
|
|
|
cp.AddContact(onion, onion, model.AuthApproved)
|
2019-11-05 22:15:56 +00:00
|
|
|
}
|
2019-01-21 20:08:03 +00:00
|
|
|
cp.eventBus.Publish(event.NewEvent(event.PeerRequest, map[event.Field]string{event.RemotePeer: onion}))
|
2018-03-09 20:44:13 +00:00
|
|
|
}
|
|
|
|
|
2019-08-07 05:27:11 +00:00
|
|
|
// DeleteContact deletes a peer from the profile, storage, and handling
|
|
|
|
func (cp *cwtchPeer) DeleteContact(onion string) {
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Lock()
|
2019-08-07 05:27:11 +00:00
|
|
|
cp.Profile.DeleteContact(onion)
|
2020-02-03 18:46:15 +00:00
|
|
|
defer cp.mutex.Unlock()
|
2019-08-07 05:27:11 +00:00
|
|
|
cp.eventBus.Publish(event.NewEventList(event.DeleteContact, event.RemotePeer, onion))
|
|
|
|
}
|
|
|
|
|
|
|
|
// DeleteGroup deletes a Group from the profile, storage, and handling
|
|
|
|
func (cp *cwtchPeer) DeleteGroup(groupID string) {
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Lock()
|
2019-08-07 05:27:11 +00:00
|
|
|
cp.Profile.DeleteGroup(groupID)
|
2020-02-03 18:46:15 +00:00
|
|
|
defer cp.mutex.Unlock()
|
2019-08-07 05:27:11 +00:00
|
|
|
cp.eventBus.Publish(event.NewEventList(event.DeleteGroup, event.GroupID, groupID))
|
|
|
|
}
|
|
|
|
|
2018-03-09 20:44:13 +00:00
|
|
|
// InviteOnionToGroup kicks off the invite process
|
2018-06-19 22:28:44 +00:00
|
|
|
func (cp *cwtchPeer) InviteOnionToGroup(onion string, groupid string) error {
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Lock()
|
2019-10-31 21:39:31 +00:00
|
|
|
group := cp.Profile.GetGroup(groupid)
|
2019-01-04 21:44:21 +00:00
|
|
|
if group == nil {
|
2021-05-04 19:23:25 +00:00
|
|
|
cp.mutex.Unlock()
|
2019-01-04 21:44:21 +00:00
|
|
|
return errors.New("invalid group id")
|
2018-03-15 20:53:22 +00:00
|
|
|
}
|
2021-05-03 23:32:48 +00:00
|
|
|
invite, err := group.Invite()
|
|
|
|
cp.mutex.Unlock()
|
2019-01-04 21:44:21 +00:00
|
|
|
if err == nil {
|
2021-05-03 23:32:48 +00:00
|
|
|
cp.SendMessageToPeer(onion, invite)
|
2019-01-04 21:44:21 +00:00
|
|
|
}
|
|
|
|
return err
|
2018-03-30 21:16:51 +00:00
|
|
|
}
|
|
|
|
|
2018-05-16 21:31:06 +00:00
|
|
|
// JoinServer manages a new server connection with the given onion address
|
2020-09-21 21:26:28 +00:00
|
|
|
func (cp *cwtchPeer) JoinServer(onion string) error {
|
2020-07-14 00:46:05 +00:00
|
|
|
if cp.GetContact(onion) != nil {
|
2020-07-22 17:14:32 +00:00
|
|
|
tokenY, yExists := cp.GetContact(onion).GetAttribute(string(model.KeyTypePrivacyPass))
|
|
|
|
tokenOnion, onionExists := cp.GetContact(onion).GetAttribute(string(model.KeyTypeTokenOnion))
|
2020-07-14 00:46:05 +00:00
|
|
|
if yExists && onionExists {
|
|
|
|
cp.eventBus.Publish(event.NewEvent(event.JoinServer, map[event.Field]string{event.GroupServer: onion, event.ServerTokenY: tokenY, event.ServerTokenOnion: tokenOnion}))
|
2020-09-21 21:26:28 +00:00
|
|
|
return nil
|
2020-07-14 00:46:05 +00:00
|
|
|
}
|
|
|
|
}
|
2020-09-21 21:26:28 +00:00
|
|
|
return errors.New("no keys found for server connection")
|
2018-03-09 20:44:13 +00:00
|
|
|
}
|
|
|
|
|
2020-11-05 21:26:03 +00:00
|
|
|
// SendMessageToGroupTracked attempts to sent the given message to the given group id.
|
2019-02-19 20:18:25 +00:00
|
|
|
// It returns the signature of the message which can be used to identify it in any UX layer.
|
|
|
|
func (cp *cwtchPeer) SendMessageToGroupTracked(groupid string, message string) (string, error) {
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Lock()
|
2019-10-31 21:39:31 +00:00
|
|
|
group := cp.Profile.GetGroup(groupid)
|
2020-02-03 18:46:15 +00:00
|
|
|
defer cp.mutex.Unlock()
|
|
|
|
|
2018-05-03 04:12:45 +00:00
|
|
|
if group == nil {
|
2019-02-19 20:18:25 +00:00
|
|
|
return "", errors.New("invalid group id")
|
2018-05-09 19:09:00 +00:00
|
|
|
}
|
2018-06-22 18:11:23 +00:00
|
|
|
ct, sig, err := cp.Profile.EncryptMessageToGroup(message, groupid)
|
2019-01-04 21:44:21 +00:00
|
|
|
|
|
|
|
if err == nil {
|
2021-03-24 21:42:15 +00:00
|
|
|
cp.eventBus.Publish(event.NewEvent(event.SendMessageToGroup, map[event.Field]string{event.GroupServer: group.GroupServer, event.Ciphertext: base64.StdEncoding.EncodeToString(ct), event.Signature: base64.StdEncoding.EncodeToString(sig)}))
|
2018-03-30 21:16:51 +00:00
|
|
|
}
|
2019-01-04 21:44:21 +00:00
|
|
|
|
2019-02-19 20:18:25 +00:00
|
|
|
return string(sig), err
|
2018-03-09 20:44:13 +00:00
|
|
|
}
|
|
|
|
|
2019-01-15 20:59:54 +00:00
|
|
|
func (cp *cwtchPeer) SendMessageToPeer(onion string, message string) string {
|
2019-01-21 20:08:03 +00:00
|
|
|
event := event.NewEvent(event.SendMessageToPeer, map[event.Field]string{event.RemotePeer: onion, event.Data: message})
|
2019-10-18 23:56:10 +00:00
|
|
|
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Lock()
|
2020-10-16 05:39:57 +00:00
|
|
|
contact, _ := cp.Profile.GetContact(onion)
|
|
|
|
event.EventID = strconv.Itoa(contact.Timeline.Len())
|
2019-10-18 23:56:10 +00:00
|
|
|
cp.Profile.AddSentMessageToContactTimeline(onion, message, time.Now(), event.EventID)
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Unlock()
|
2019-10-18 23:56:10 +00:00
|
|
|
|
2020-10-16 05:39:57 +00:00
|
|
|
cp.eventBus.Publish(event)
|
|
|
|
|
2019-01-15 20:59:54 +00:00
|
|
|
return event.EventID
|
2019-01-04 21:44:21 +00:00
|
|
|
}
|
|
|
|
|
2020-03-07 07:41:00 +00:00
|
|
|
func (cp *cwtchPeer) SendGetValToPeer(onion string, scope string, path string) {
|
|
|
|
event := event.NewEventList(event.SendGetValMessageToPeer, event.RemotePeer, onion, event.Scope, scope, event.Path, path)
|
|
|
|
cp.eventBus.Publish(event)
|
|
|
|
}
|
|
|
|
|
2018-05-16 21:31:06 +00:00
|
|
|
// BlockPeer blocks an existing peer relationship.
|
2020-06-16 00:16:04 +00:00
|
|
|
func (cp *cwtchPeer) SetContactAuthorization(peer string, authorization model.Authorization) error {
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Lock()
|
2020-06-16 00:16:04 +00:00
|
|
|
err := cp.Profile.SetContactAuthorization(peer, authorization)
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Unlock()
|
2020-06-16 00:16:04 +00:00
|
|
|
cp.eventBus.Publish(event.NewEvent(event.SetPeerAuthorization, map[event.Field]string{event.RemotePeer: peer, event.Authorization: string(authorization)}))
|
2019-08-07 18:49:44 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2018-05-16 21:31:06 +00:00
|
|
|
// AcceptInvite accepts a given existing group invite
|
2018-06-19 22:28:44 +00:00
|
|
|
func (cp *cwtchPeer) AcceptInvite(groupID string) error {
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Lock()
|
2019-04-23 20:30:50 +00:00
|
|
|
err := cp.Profile.AcceptInvite(groupID)
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Unlock()
|
2019-04-23 20:30:50 +00:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-02-14 01:57:42 +00:00
|
|
|
cp.eventBus.Publish(event.NewEvent(event.AcceptGroupInvite, map[event.Field]string{event.GroupID: groupID}))
|
2019-04-23 20:30:50 +00:00
|
|
|
cp.JoinServer(cp.Profile.Groups[groupID].GroupServer)
|
|
|
|
|
|
|
|
return nil
|
2018-05-03 04:12:45 +00:00
|
|
|
}
|
|
|
|
|
2018-05-16 21:31:06 +00:00
|
|
|
// RejectInvite rejects a given group invite.
|
2018-06-19 22:28:44 +00:00
|
|
|
func (cp *cwtchPeer) RejectInvite(groupID string) {
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Lock()
|
|
|
|
defer cp.mutex.Unlock()
|
2018-05-30 17:41:02 +00:00
|
|
|
cp.Profile.RejectInvite(groupID)
|
2021-04-28 21:45:41 +00:00
|
|
|
cp.eventBus.Publish(event.NewEvent(event.RejectGroupInvite, map[event.Field]string{event.GroupID: groupID}))
|
2018-05-30 17:41:02 +00:00
|
|
|
}
|
|
|
|
|
2019-05-15 20:12:11 +00:00
|
|
|
// Listen makes the peer open a listening port to accept incoming connections (and be detactably online)
|
2018-11-10 22:14:12 +00:00
|
|
|
func (cp *cwtchPeer) Listen() {
|
2021-04-13 22:12:12 +00:00
|
|
|
cp.mutex.Lock()
|
|
|
|
defer cp.mutex.Unlock()
|
|
|
|
if cp.listenStatus == false {
|
|
|
|
log.Infof("cwtchPeer Listen sending ProtocolEngineStartListen\n")
|
|
|
|
cp.listenStatus = true
|
|
|
|
cp.eventBus.Publish(event.NewEvent(event.ProtocolEngineStartListen, map[event.Field]string{event.Onion: cp.Profile.Onion}))
|
|
|
|
} else {
|
|
|
|
// protocol engine is already listening
|
|
|
|
}
|
2018-03-09 20:44:13 +00:00
|
|
|
}
|
|
|
|
|
2020-10-29 21:22:33 +00:00
|
|
|
// StartPeersConnections attempts to connect to peer connections
|
2019-05-15 20:12:11 +00:00
|
|
|
func (cp *cwtchPeer) StartPeersConnections() {
|
2020-10-29 21:22:33 +00:00
|
|
|
for _, contact := range cp.GetContacts() {
|
|
|
|
if cp.GetContact(contact).IsServer() == false {
|
|
|
|
cp.PeerWithOnion(contact)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// StartServerConnections attempts to connect to all server connections
|
|
|
|
func (cp *cwtchPeer) StartServerConnections() {
|
2019-05-15 20:12:11 +00:00
|
|
|
for _, contact := range cp.GetContacts() {
|
2020-09-21 21:26:28 +00:00
|
|
|
if cp.GetContact(contact).IsServer() {
|
|
|
|
cp.JoinServer(contact)
|
2019-05-15 20:12:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-31 21:39:31 +00:00
|
|
|
// SetAttribute sets an attribute for this profile and emits an event
|
|
|
|
func (cp *cwtchPeer) SetAttribute(key string, val string) {
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Lock()
|
2019-10-31 21:39:31 +00:00
|
|
|
cp.Profile.SetAttribute(key, val)
|
2020-02-03 18:46:15 +00:00
|
|
|
defer cp.mutex.Unlock()
|
2019-10-31 21:39:31 +00:00
|
|
|
cp.eventBus.Publish(event.NewEvent(event.SetAttribute, map[event.Field]string{
|
|
|
|
event.Key: key,
|
|
|
|
event.Data: val,
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetAttribute gets an attribute for the profile
|
|
|
|
func (cp *cwtchPeer) GetAttribute(key string) (string, bool) {
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Lock()
|
|
|
|
defer cp.mutex.Unlock()
|
2020-03-07 07:41:00 +00:00
|
|
|
if val, exists := cp.Profile.GetAttribute(key); exists {
|
|
|
|
return val, true
|
|
|
|
}
|
2021-05-03 23:32:48 +00:00
|
|
|
|
|
|
|
if key == attr.GetLocalScope("name") {
|
|
|
|
return cp.Profile.Name, true
|
|
|
|
}
|
|
|
|
|
2020-03-07 07:41:00 +00:00
|
|
|
return "", false
|
2019-10-31 21:39:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// SetContactAttribute sets an attribute for the indicated contact and emits an event
|
|
|
|
func (cp *cwtchPeer) SetContactAttribute(onion string, key string, val string) {
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Lock()
|
|
|
|
defer cp.mutex.Unlock()
|
2019-10-31 21:39:31 +00:00
|
|
|
if contact, ok := cp.Profile.GetContact(onion); ok {
|
|
|
|
contact.SetAttribute(key, val)
|
|
|
|
cp.eventBus.Publish(event.NewEvent(event.SetPeerAttribute, map[event.Field]string{
|
|
|
|
event.RemotePeer: onion,
|
|
|
|
event.Key: key,
|
|
|
|
event.Data: val,
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetContactAttribute gets an attribute for the indicated contact
|
|
|
|
func (cp *cwtchPeer) GetContactAttribute(onion string, key string) (string, bool) {
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Lock()
|
|
|
|
defer cp.mutex.Unlock()
|
2019-10-31 21:39:31 +00:00
|
|
|
if contact, ok := cp.Profile.GetContact(onion); ok {
|
2020-03-07 07:41:00 +00:00
|
|
|
if val, exists := contact.GetAttribute(key); exists {
|
|
|
|
return val, true
|
|
|
|
}
|
2019-10-31 21:39:31 +00:00
|
|
|
}
|
|
|
|
return "", false
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetGroupAttribute sets an attribute for the indicated group and emits an event
|
|
|
|
func (cp *cwtchPeer) SetGroupAttribute(gid string, key string, val string) {
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Lock()
|
|
|
|
defer cp.mutex.Unlock()
|
2019-10-31 21:39:31 +00:00
|
|
|
if group := cp.Profile.GetGroup(gid); group != nil {
|
|
|
|
group.SetAttribute(key, val)
|
|
|
|
cp.eventBus.Publish(event.NewEvent(event.SetGroupAttribute, map[event.Field]string{
|
|
|
|
event.GroupID: gid,
|
|
|
|
event.Key: key,
|
|
|
|
event.Data: val,
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetGroupAttribute gets an attribute for the indicated group
|
|
|
|
func (cp *cwtchPeer) GetGroupAttribute(gid string, key string) (string, bool) {
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Lock()
|
|
|
|
defer cp.mutex.Unlock()
|
2019-10-31 21:39:31 +00:00
|
|
|
if group := cp.Profile.GetGroup(gid); group != nil {
|
2020-03-07 07:41:00 +00:00
|
|
|
if val, exists := group.GetAttribute(key); exists {
|
|
|
|
return val, true
|
|
|
|
}
|
2019-10-31 21:39:31 +00:00
|
|
|
}
|
|
|
|
return "", false
|
|
|
|
}
|
|
|
|
|
2018-06-15 16:21:07 +00:00
|
|
|
// Shutdown kills all connections and cleans up all goroutines for the peer
|
2018-06-19 22:28:44 +00:00
|
|
|
func (cp *cwtchPeer) Shutdown() {
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Lock()
|
|
|
|
defer cp.mutex.Unlock()
|
2018-11-10 22:14:12 +00:00
|
|
|
cp.shutdown = true
|
2019-01-04 21:44:21 +00:00
|
|
|
cp.queue.Shutdown()
|
2018-05-30 18:42:17 +00:00
|
|
|
}
|
|
|
|
|
2020-10-03 23:09:47 +00:00
|
|
|
func (cp *cwtchPeer) StoreMessage(onion string, messageTxt string, sent time.Time) {
|
2020-11-12 21:17:06 +00:00
|
|
|
if cp.GetContact(onion) == nil {
|
|
|
|
cp.AddContact(onion, onion, model.AuthUnknown)
|
|
|
|
}
|
2020-10-03 23:09:47 +00:00
|
|
|
cp.mutex.Lock()
|
|
|
|
cp.Profile.AddMessageToContactTimeline(onion, messageTxt, sent)
|
|
|
|
cp.mutex.Unlock()
|
|
|
|
}
|
|
|
|
|
2019-01-04 21:44:21 +00:00
|
|
|
// eventHandler process events from other subsystems
|
|
|
|
func (cp *cwtchPeer) eventHandler() {
|
|
|
|
for {
|
|
|
|
ev := cp.queue.Next()
|
|
|
|
switch ev.EventType {
|
2019-09-19 23:14:35 +00:00
|
|
|
/***** Default auto handled events *****/
|
2021-04-13 22:12:12 +00:00
|
|
|
case event.ProtocolEngineStopped:
|
|
|
|
cp.mutex.Lock()
|
|
|
|
cp.listenStatus = false
|
|
|
|
log.Infof("Protocol engine for %v has stopped listening", cp.Profile.Onion)
|
|
|
|
cp.mutex.Unlock()
|
2019-01-04 21:44:21 +00:00
|
|
|
case event.EncryptedGroupMessage:
|
2019-10-18 23:56:10 +00:00
|
|
|
// If successful, a side effect is the message is added to the group's timeline
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Lock()
|
2021-03-29 18:53:02 +00:00
|
|
|
ciphertext, _ := base64.StdEncoding.DecodeString(ev.Data[event.Ciphertext])
|
|
|
|
signature, _ := base64.StdEncoding.DecodeString(ev.Data[event.Signature])
|
2021-03-24 21:42:15 +00:00
|
|
|
ok, groupID, message, seen := cp.Profile.AttemptDecryption(ciphertext, signature)
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Unlock()
|
2019-02-03 03:24:42 +00:00
|
|
|
if ok && !seen {
|
2021-04-28 19:47:55 +00:00
|
|
|
cp.eventBus.Publish(event.NewEvent(event.NewMessageFromGroup, map[event.Field]string{event.TimestampReceived: message.Received.Format(time.RFC3339Nano), event.TimestampSent: message.Timestamp.Format(time.RFC3339Nano), event.Data: message.Message, event.GroupID: groupID, event.Signature: base64.StdEncoding.EncodeToString(message.Signature), event.PreviousSignature: base64.StdEncoding.EncodeToString(message.PreviousMessageSig), event.RemotePeer: message.PeerID}))
|
2019-01-04 21:44:21 +00:00
|
|
|
}
|
2019-09-19 23:14:35 +00:00
|
|
|
|
2019-10-18 23:56:10 +00:00
|
|
|
case event.NewMessageFromPeer: //event.TimestampReceived, event.RemotePeer, event.Data
|
2020-10-03 23:49:05 +00:00
|
|
|
ts, _ := time.Parse(time.RFC3339Nano, ev.Data[event.TimestampReceived])
|
2020-10-03 23:09:47 +00:00
|
|
|
cp.StoreMessage(ev.Data[event.RemotePeer], ev.Data[event.Data], ts)
|
2019-10-18 23:56:10 +00:00
|
|
|
|
|
|
|
case event.PeerAcknowledgement:
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Lock()
|
2021-05-03 18:35:35 +00:00
|
|
|
idx := cp.Profile.AckSentMessageToPeer(ev.Data[event.RemotePeer], ev.Data[event.EventID])
|
|
|
|
edata := ev.Data
|
|
|
|
edata[event.Index] = strconv.Itoa(idx)
|
|
|
|
cp.eventBus.Publish(event.NewEvent(event.IndexedAcknowledgement, edata))
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Unlock()
|
2019-10-18 23:56:10 +00:00
|
|
|
|
|
|
|
case event.SendMessageToGroupError:
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Lock()
|
2019-10-18 23:56:10 +00:00
|
|
|
cp.Profile.AddGroupSentMessageError(ev.Data[event.GroupServer], ev.Data[event.Signature], ev.Data[event.Error])
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Unlock()
|
2019-10-18 23:56:10 +00:00
|
|
|
|
|
|
|
case event.SendMessageToPeerError:
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Lock()
|
2019-10-18 23:56:10 +00:00
|
|
|
cp.Profile.ErrorSentMessageToPeer(ev.Data[event.RemotePeer], ev.Data[event.EventID], ev.Data[event.Error])
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Unlock()
|
2021-04-28 19:47:55 +00:00
|
|
|
case event.RetryServerRequest:
|
|
|
|
// Automated Join Server Request triggered by a plugin.
|
|
|
|
log.Debugf("profile received an automated retry event for %v", ev.Data[event.GroupServer])
|
|
|
|
cp.JoinServer(ev.Data[event.GroupServer])
|
2020-03-07 07:41:00 +00:00
|
|
|
case event.NewGetValMessageFromPeer:
|
|
|
|
onion := ev.Data[event.RemotePeer]
|
|
|
|
scope := ev.Data[event.Scope]
|
|
|
|
path := ev.Data[event.Path]
|
|
|
|
|
|
|
|
log.Debugf("NewGetValMessageFromPeer for %v%v from %v\n", scope, path, onion)
|
|
|
|
|
2020-11-12 21:17:06 +00:00
|
|
|
remotePeer := cp.GetContact(onion)
|
|
|
|
if remotePeer != nil && remotePeer.Authorization == model.AuthApproved {
|
|
|
|
if scope == attr.PublicScope {
|
|
|
|
val, exists := cp.GetAttribute(attr.GetPublicScope(path))
|
|
|
|
resp := event.NewEvent(event.SendRetValMessageToPeer, map[event.Field]string{event.RemotePeer: onion, event.Exists: strconv.FormatBool(exists)})
|
|
|
|
resp.EventID = ev.EventID
|
|
|
|
if exists {
|
|
|
|
resp.Data[event.Data] = val
|
|
|
|
} else {
|
|
|
|
resp.Data[event.Data] = ""
|
|
|
|
}
|
|
|
|
log.Debugf("Responding with SendRetValMessageToPeer exists:%v data: %v\n", exists, val)
|
|
|
|
|
|
|
|
cp.eventBus.Publish(resp)
|
2020-03-07 07:41:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-04-17 00:00:17 +00:00
|
|
|
/***** Non default but requestable handlable events *****/
|
|
|
|
|
2020-03-07 07:41:00 +00:00
|
|
|
case event.NewRetValMessageFromPeer:
|
|
|
|
onion := ev.Data[event.RemotePeer]
|
|
|
|
scope := ev.Data[event.Scope]
|
|
|
|
path := ev.Data[event.Path]
|
|
|
|
val := ev.Data[event.Data]
|
|
|
|
exists, _ := strconv.ParseBool(ev.Data[event.Exists])
|
|
|
|
log.Debugf("NewRetValMessageFromPeer %v %v%v %v %v\n", onion, scope, path, exists, val)
|
|
|
|
if exists {
|
|
|
|
if scope == attr.PublicScope {
|
|
|
|
cp.SetContactAttribute(onion, attr.GetPeerScope(path), val)
|
|
|
|
}
|
|
|
|
}
|
2019-05-15 20:12:11 +00:00
|
|
|
case event.PeerStateChange:
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Lock()
|
2019-05-15 20:12:11 +00:00
|
|
|
if _, exists := cp.Profile.Contacts[ev.Data[event.RemotePeer]]; exists {
|
|
|
|
cp.Profile.Contacts[ev.Data[event.RemotePeer]].State = ev.Data[event.ConnectionState]
|
|
|
|
}
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Unlock()
|
2019-05-15 20:12:11 +00:00
|
|
|
case event.ServerStateChange:
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Lock()
|
2019-05-15 20:12:11 +00:00
|
|
|
for _, group := range cp.Profile.Groups {
|
|
|
|
if group.GroupServer == ev.Data[event.GroupServer] {
|
|
|
|
group.State = ev.Data[event.ConnectionState]
|
|
|
|
}
|
|
|
|
}
|
2020-02-03 18:46:15 +00:00
|
|
|
cp.mutex.Unlock()
|
2021-04-28 19:47:55 +00:00
|
|
|
|
2019-01-04 21:44:21 +00:00
|
|
|
default:
|
|
|
|
if ev.EventType != "" {
|
2019-01-13 23:48:17 +00:00
|
|
|
log.Errorf("peer event handler received an event it was not subscribed for: %v", ev.EventType)
|
2019-01-04 21:44:21 +00:00
|
|
|
}
|
2019-01-21 20:08:03 +00:00
|
|
|
return
|
2019-01-04 21:44:21 +00:00
|
|
|
}
|
|
|
|
}
|
2018-10-04 19:15:03 +00:00
|
|
|
}
|