forked from cwtch.im/cwtch
Merge branch 'blocking-thread-safe' of cwtch.im/cwtch into master
This commit is contained in:
commit
c7c66a73d5
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -14,4 +14,5 @@ const (
|
|||
CONNECTED
|
||||
AUTHENTICATED
|
||||
FAILED
|
||||
KILLED
|
||||
)
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
cp.Profile.Contacts[peer].Trusted = true
|
||||
err := cp.Profile.TrustPeer(peer)
|
||||
if err == nil {
|
||||
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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue