Making profile thread safe, making blocking do something

This commit is contained in:
Sarah Jamie Lewis 2018-05-30 10:41:02 -07:00
parent becfe7c928
commit ded21271f6
6 changed files with 130 additions and 33 deletions

View File

@ -13,6 +13,7 @@ import (
"io"
"io/ioutil"
"strconv"
"sync"
"time"
)
@ -32,6 +33,7 @@ type Profile struct {
Ed25519PrivateKey ed25519.PrivateKey
OnionPrivateKey *rsa.PrivateKey
Groups map[string]*Group
lock sync.Mutex
}
// GenerateNewProfile creates a new profile, with new encryption and signing keys, and a profile name.
@ -78,7 +80,74 @@ func (p *Profile) AddCwtchIdentity(onion string, ci *protocol.CwtchIdentity) {
// AddContact allows direct manipulation of cwtch contacts
func (p *Profile) AddContact(onion string, profile *PublicProfile) {
p.lock.Lock()
p.Contacts[onion] = profile
p.lock.Unlock()
}
// RejectInvite rejects and removes a group invite
func (p *Profile) RejectInvite(groupID string) {
p.lock.Lock()
delete(p.Groups, groupID)
p.lock.Unlock()
}
// AcceptInvite accepts a group invite
func (p *Profile) AcceptInvite(groupID string) error {
p.lock.Lock()
group, ok := p.Groups[groupID]
if ok {
group.Accepted = true
}
p.lock.Unlock()
if !ok {
return errors.New("group does not exist")
}
return nil
}
// BlockPeer blocks a contact
func (p *Profile) BlockPeer(onion string) error {
p.lock.Lock()
contact, ok := p.Contacts[onion]
if ok {
contact.Blocked = true
}
p.lock.Unlock()
if !ok {
return errors.New("peer does not exist")
}
return nil
}
// TrustPeer sets a contact to trusted
func (p *Profile) TrustPeer(onion string) error {
p.lock.Lock()
contact, ok := p.Contacts[onion]
if ok {
contact.Trusted = true
}
p.lock.Unlock()
if !ok {
return errors.New("peer does not exist")
}
return nil
}
// IsBlocked returns true if the contact has been blocked, false otherwise
func (p *Profile) IsBlocked(onion string) bool {
contact, ok := p.GetContact(onion)
if ok {
return contact.Blocked
}
return false
}
func (p *Profile) GetContact(onion string) (*PublicProfile, bool) {
p.lock.Lock()
contact, ok := p.Contacts[onion]
p.lock.Unlock()
return contact, ok
}
// VerifyGroupMessage confirms the authenticity of a message given an onion, message and signature.
@ -89,7 +158,7 @@ func (p *Profile) VerifyGroupMessage(onion string, groupID string, message strin
return ed25519.Verify(p.Ed25519PublicKey, []byte(m), signature)
}
contact, found := p.Contacts[onion]
contact, found := p.GetContact(onion)
if found {
m := message + groupID + strconv.Itoa(int(timestamp))
return ed25519.Verify(contact.Ed25519PublicKey, []byte(m), signature)
@ -111,13 +180,18 @@ func (p *Profile) StartGroup(server string) (groupID string, invite []byte, err
signedGroupID := p.SignMessage(groupID + server)
group.SignGroup(signedGroupID)
invite, err = group.Invite()
p.lock.Lock()
p.Groups[group.GroupID] = group
p.lock.Unlock()
return
}
// GetGroupByGroupID a pointer to a Group by the group Id, returns nil if no group found.
func (p *Profile) GetGroupByGroupID(groupID string) *Group {
return p.Groups[groupID]
func (p *Profile) GetGroupByGroupID(groupID string) (g *Group) {
p.lock.Lock()
g = p.Groups[groupID]
p.lock.Unlock()
return g
}
// ProcessInvite adds a new group invite to the profile.
@ -134,17 +208,23 @@ func (p *Profile) ProcessInvite(gci *protocol.GroupChatInvite, peerHostname stri
// AddGroup is a convenience method for adding a group to a profile.
func (p *Profile) AddGroup(group *Group) {
p.lock.Lock()
existingGroup, exists := p.Groups[group.GroupID]
p.lock.Unlock()
if !exists {
owner, ok := p.Contacts[group.Owner]
owner, ok := p.GetContact(group.Owner)
if ok {
valid := ed25519.Verify(owner.Ed25519PublicKey, []byte(group.GroupID+group.GroupServer), group.SignedGroupID)
if valid {
p.lock.Lock()
p.Groups[group.GroupID] = group
p.lock.Unlock()
}
}
} else if exists && existingGroup.Owner == group.Owner {
p.lock.Lock()
p.Groups[group.GroupID] = group
p.lock.Unlock()
}
// If we are sent an invite or group update by someone who is not an owner
@ -187,7 +267,7 @@ func getRandomness(arr *[]byte) {
// EncryptMessageToGroup when given a message and a group, encrypts and signs the message under the group and
// profile
func (p *Profile) EncryptMessageToGroup(message string, groupID string) ([]byte, error) {
group := p.Groups[groupID]
group := p.GetGroupByGroupID(groupID)
if group != nil {
timestamp := time.Now().Unix()
signature := p.SignMessage(message + groupID + strconv.Itoa(int(timestamp)))
@ -219,7 +299,9 @@ func (p *Profile) EncryptMessageToGroup(message string, groupID string) ([]byte,
// Save makes a opy of the profile in the given file
func (p *Profile) Save(profilefile string) error {
p.lock.Lock()
bytes, _ := json.Marshal(p)
p.lock.Unlock()
return ioutil.WriteFile(profilefile, bytes, 0600)
}

View File

@ -50,6 +50,17 @@ func (m *Manager) ManageServerConnection(host string, handler func(string, *prot
m.lock.Unlock()
}
// TearDownPeerConnection closes an existing peer connection
func (m *Manager) TearDownPeerConnection(onion string) {
m.lock.Lock()
pc, ok := m.peerConnections[onion]
if ok {
pc.Kill()
delete(m.peerConnections, onion)
}
m.lock.Unlock()
}
// GetPeers returns a map of all peer connections with their state
func (m *Manager) GetPeers() map[string]ConnectionState {
rm := make(map[string]ConnectionState)

View File

@ -103,3 +103,10 @@ func (ppc *PeerPeerConnection) Run() error {
ppc.state = FAILED
return err
}
// Kill closes the connection
func (ppc *PeerPeerConnection) Kill() {
ppc.state = KILLED
ppc.connection.Break()
// TODO We should kill the connection outright, but we need to add that to libricochet-go
}

View File

@ -14,4 +14,5 @@ const (
CONNECTED
AUTHENTICATED
FAILED
KILLED
)

View File

@ -1,6 +1,7 @@
package peer
import (
"crypto/rsa"
"cwtch.im/cwtch/model"
"cwtch.im/cwtch/peer/connections"
"cwtch.im/cwtch/peer/peer"
@ -147,44 +148,39 @@ func (cp *CwtchPeer) GetServers() map[string]connections.ConnectionState {
// TrustPeer sets an existing peer relationship to trusted
func (cp *CwtchPeer) TrustPeer(peer string) error {
_, ok := cp.Profile.Contacts[peer]
if !ok {
return errors.New("peer does not exist")
err := cp.Profile.TrustPeer(peer)
if err == nil {
cp.PeerWithOnion(peer)
}
cp.Profile.Contacts[peer].Trusted = true
cp.PeerWithOnion(peer)
return nil
return err
}
// BlockPeer blocks an existing peer relationship.
func (cp *CwtchPeer) BlockPeer(peer string) error {
_, ok := cp.Profile.Contacts[peer]
if !ok {
return errors.New("peer does not exist")
}
cp.Profile.Contacts[peer].Blocked = true
return nil
err := cp.Profile.BlockPeer(peer)
cp.connectionsManager.TearDownConnection(peer)
return err
}
// AcceptInvite accepts a given existing group invite
func (cp *CwtchPeer) AcceptInvite(groupID string) error {
g := cp.Profile.GetGroupByGroupID(groupID)
if g == nil {
return errors.New("group invite does not exit")
}
g.Accepted = true
return nil
return cp.Profile.AcceptInvite(groupID)
}
// RejectInvite rejects a given group invite.
func (cp *CwtchPeer) RejectInvite(groupID string) error {
g := cp.Profile.GetGroupByGroupID(groupID)
if g == nil {
return errors.New("group invite does not exit")
}
g.Accepted = false
// TODO delete group from Profile
return nil
func (cp *CwtchPeer) RejectInvite(groupID string) {
cp.Profile.RejectInvite(groupID)
}
// LookupContact returns that a contact is known and allowed to communicate for all cases.
func (cp *CwtchPeer) LookupContact(hostname string, publicKey rsa.PublicKey) (allowed, known bool) {
blocked := cp.Profile.IsBlocked(hostname)
return !blocked, true
}
// ContactRequest needed to implement ContactRequestHandler Interface
func (cp *CwtchPeer) ContactRequest(name string, message string) string {
return "Accepted"
}
// Listen sets up an onion listener to process incoming cwtch messages
@ -208,7 +204,7 @@ func (cp *CwtchPeer) Listen() error {
}
})
cwtchpeer.Init(cp.Profile.Name, cp.Profile.OnionPrivateKey, af, new(application.AcceptAllContactManager))
cwtchpeer.Init(cp.Profile.Name, cp.Profile.OnionPrivateKey, af, cp)
log.Printf("Running cwtch peer on %v", l.Addr().String())
cwtchpeer.Run(l)
return nil

View File

@ -66,7 +66,7 @@ func (s *Server) Run(privateKeyFile string) {
}
})
cwtchserver.Init("cwtch server for " + l.Addr().String()[0:16], pk, af, new(application.AcceptAllContactManager))
cwtchserver.Init("cwtch server for "+l.Addr().String()[0:16], pk, af, new(application.AcceptAllContactManager))
log.Printf("cwtch server running on cwtch:%s", l.Addr().String()[0:16])
cwtchserver.Run(l)
}