forked from cwtch.im/cwtch
Making profile thread safe, making blocking do something
This commit is contained in:
parent
becfe7c928
commit
ded21271f6
|
@ -13,6 +13,7 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -32,6 +33,7 @@ type Profile struct {
|
||||||
Ed25519PrivateKey ed25519.PrivateKey
|
Ed25519PrivateKey ed25519.PrivateKey
|
||||||
OnionPrivateKey *rsa.PrivateKey
|
OnionPrivateKey *rsa.PrivateKey
|
||||||
Groups map[string]*Group
|
Groups map[string]*Group
|
||||||
|
lock sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateNewProfile creates a new profile, with new encryption and signing keys, and a profile name.
|
// 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
|
// AddContact allows direct manipulation of cwtch contacts
|
||||||
func (p *Profile) AddContact(onion string, profile *PublicProfile) {
|
func (p *Profile) AddContact(onion string, profile *PublicProfile) {
|
||||||
|
p.lock.Lock()
|
||||||
p.Contacts[onion] = profile
|
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.
|
// 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)
|
return ed25519.Verify(p.Ed25519PublicKey, []byte(m), signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
contact, found := p.Contacts[onion]
|
contact, found := p.GetContact(onion)
|
||||||
if found {
|
if found {
|
||||||
m := message + groupID + strconv.Itoa(int(timestamp))
|
m := message + groupID + strconv.Itoa(int(timestamp))
|
||||||
return ed25519.Verify(contact.Ed25519PublicKey, []byte(m), signature)
|
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)
|
signedGroupID := p.SignMessage(groupID + server)
|
||||||
group.SignGroup(signedGroupID)
|
group.SignGroup(signedGroupID)
|
||||||
invite, err = group.Invite()
|
invite, err = group.Invite()
|
||||||
|
p.lock.Lock()
|
||||||
p.Groups[group.GroupID] = group
|
p.Groups[group.GroupID] = group
|
||||||
|
p.lock.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetGroupByGroupID a pointer to a Group by the group Id, returns nil if no group found.
|
// GetGroupByGroupID a pointer to a Group by the group Id, returns nil if no group found.
|
||||||
func (p *Profile) GetGroupByGroupID(groupID string) *Group {
|
func (p *Profile) GetGroupByGroupID(groupID string) (g *Group) {
|
||||||
return p.Groups[groupID]
|
p.lock.Lock()
|
||||||
|
g = p.Groups[groupID]
|
||||||
|
p.lock.Unlock()
|
||||||
|
return g
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessInvite adds a new group invite to the profile.
|
// 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.
|
// AddGroup is a convenience method for adding a group to a profile.
|
||||||
func (p *Profile) AddGroup(group *Group) {
|
func (p *Profile) AddGroup(group *Group) {
|
||||||
|
p.lock.Lock()
|
||||||
existingGroup, exists := p.Groups[group.GroupID]
|
existingGroup, exists := p.Groups[group.GroupID]
|
||||||
|
p.lock.Unlock()
|
||||||
if !exists {
|
if !exists {
|
||||||
owner, ok := p.Contacts[group.Owner]
|
owner, ok := p.GetContact(group.Owner)
|
||||||
if ok {
|
if ok {
|
||||||
valid := ed25519.Verify(owner.Ed25519PublicKey, []byte(group.GroupID+group.GroupServer), group.SignedGroupID)
|
valid := ed25519.Verify(owner.Ed25519PublicKey, []byte(group.GroupID+group.GroupServer), group.SignedGroupID)
|
||||||
if valid {
|
if valid {
|
||||||
|
p.lock.Lock()
|
||||||
p.Groups[group.GroupID] = group
|
p.Groups[group.GroupID] = group
|
||||||
|
p.lock.Unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if exists && existingGroup.Owner == group.Owner {
|
} else if exists && existingGroup.Owner == group.Owner {
|
||||||
|
p.lock.Lock()
|
||||||
p.Groups[group.GroupID] = group
|
p.Groups[group.GroupID] = group
|
||||||
|
p.lock.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we are sent an invite or group update by someone who is not an owner
|
// 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
|
// EncryptMessageToGroup when given a message and a group, encrypts and signs the message under the group and
|
||||||
// profile
|
// profile
|
||||||
func (p *Profile) EncryptMessageToGroup(message string, groupID string) ([]byte, error) {
|
func (p *Profile) EncryptMessageToGroup(message string, groupID string) ([]byte, error) {
|
||||||
group := p.Groups[groupID]
|
group := p.GetGroupByGroupID(groupID)
|
||||||
if group != nil {
|
if group != nil {
|
||||||
timestamp := time.Now().Unix()
|
timestamp := time.Now().Unix()
|
||||||
signature := p.SignMessage(message + groupID + strconv.Itoa(int(timestamp)))
|
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
|
// Save makes a opy of the profile in the given file
|
||||||
func (p *Profile) Save(profilefile string) error {
|
func (p *Profile) Save(profilefile string) error {
|
||||||
|
p.lock.Lock()
|
||||||
bytes, _ := json.Marshal(p)
|
bytes, _ := json.Marshal(p)
|
||||||
|
p.lock.Unlock()
|
||||||
return ioutil.WriteFile(profilefile, bytes, 0600)
|
return ioutil.WriteFile(profilefile, bytes, 0600)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,17 @@ func (m *Manager) ManageServerConnection(host string, handler func(string, *prot
|
||||||
m.lock.Unlock()
|
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
|
// GetPeers returns a map of all peer connections with their state
|
||||||
func (m *Manager) GetPeers() map[string]ConnectionState {
|
func (m *Manager) GetPeers() map[string]ConnectionState {
|
||||||
rm := make(map[string]ConnectionState)
|
rm := make(map[string]ConnectionState)
|
||||||
|
|
|
@ -103,3 +103,10 @@ func (ppc *PeerPeerConnection) Run() error {
|
||||||
ppc.state = FAILED
|
ppc.state = FAILED
|
||||||
return err
|
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
|
CONNECTED
|
||||||
AUTHENTICATED
|
AUTHENTICATED
|
||||||
FAILED
|
FAILED
|
||||||
|
KILLED
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package peer
|
package peer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/rsa"
|
||||||
"cwtch.im/cwtch/model"
|
"cwtch.im/cwtch/model"
|
||||||
"cwtch.im/cwtch/peer/connections"
|
"cwtch.im/cwtch/peer/connections"
|
||||||
"cwtch.im/cwtch/peer/peer"
|
"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
|
// TrustPeer sets an existing peer relationship to trusted
|
||||||
func (cp *CwtchPeer) TrustPeer(peer string) error {
|
func (cp *CwtchPeer) TrustPeer(peer string) error {
|
||||||
_, ok := cp.Profile.Contacts[peer]
|
err := cp.Profile.TrustPeer(peer)
|
||||||
if !ok {
|
if err == nil {
|
||||||
return errors.New("peer does not exist")
|
cp.PeerWithOnion(peer)
|
||||||
}
|
}
|
||||||
cp.Profile.Contacts[peer].Trusted = true
|
return err
|
||||||
cp.PeerWithOnion(peer)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// BlockPeer blocks an existing peer relationship.
|
// BlockPeer blocks an existing peer relationship.
|
||||||
func (cp *CwtchPeer) BlockPeer(peer string) error {
|
func (cp *CwtchPeer) BlockPeer(peer string) error {
|
||||||
_, ok := cp.Profile.Contacts[peer]
|
err := cp.Profile.BlockPeer(peer)
|
||||||
if !ok {
|
cp.connectionsManager.TearDownConnection(peer)
|
||||||
return errors.New("peer does not exist")
|
return err
|
||||||
}
|
|
||||||
cp.Profile.Contacts[peer].Blocked = true
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// AcceptInvite accepts a given existing group invite
|
// AcceptInvite accepts a given existing group invite
|
||||||
func (cp *CwtchPeer) AcceptInvite(groupID string) error {
|
func (cp *CwtchPeer) AcceptInvite(groupID string) error {
|
||||||
g := cp.Profile.GetGroupByGroupID(groupID)
|
return cp.Profile.AcceptInvite(groupID)
|
||||||
if g == nil {
|
|
||||||
return errors.New("group invite does not exit")
|
|
||||||
}
|
|
||||||
g.Accepted = true
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RejectInvite rejects a given group invite.
|
// RejectInvite rejects a given group invite.
|
||||||
func (cp *CwtchPeer) RejectInvite(groupID string) error {
|
func (cp *CwtchPeer) RejectInvite(groupID string) {
|
||||||
g := cp.Profile.GetGroupByGroupID(groupID)
|
cp.Profile.RejectInvite(groupID)
|
||||||
if g == nil {
|
}
|
||||||
return errors.New("group invite does not exit")
|
|
||||||
}
|
// LookupContact returns that a contact is known and allowed to communicate for all cases.
|
||||||
g.Accepted = false
|
func (cp *CwtchPeer) LookupContact(hostname string, publicKey rsa.PublicKey) (allowed, known bool) {
|
||||||
// TODO delete group from Profile
|
blocked := cp.Profile.IsBlocked(hostname)
|
||||||
return nil
|
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
|
// 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())
|
log.Printf("Running cwtch peer on %v", l.Addr().String())
|
||||||
cwtchpeer.Run(l)
|
cwtchpeer.Run(l)
|
||||||
return nil
|
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])
|
log.Printf("cwtch server running on cwtch:%s", l.Addr().String()[0:16])
|
||||||
cwtchserver.Run(l)
|
cwtchserver.Run(l)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue