Merge PR #151
|
@ -23,8 +23,8 @@ func TestMessagePadding(t *testing.T) {
|
||||||
|
|
||||||
group := alice.GetGroupByGroupID(gid)
|
group := alice.GetGroupByGroupID(gid)
|
||||||
|
|
||||||
c1, s1, _ := sarah.EncryptMessageToGroup("Hello World 1", group.GroupID)
|
c1, s1, err := sarah.EncryptMessageToGroup("Hello World 1", group.GroupID)
|
||||||
t.Logf("Length of Encrypted Message: %v", len(c1))
|
t.Logf("Length of Encrypted Message: %v %v", len(c1), err)
|
||||||
alice.AttemptDecryption(c1, s1)
|
alice.AttemptDecryption(c1, s1)
|
||||||
|
|
||||||
c2, s2, _ := alice.EncryptMessageToGroup("Hello World 2", group.GroupID)
|
c2, s2, _ := alice.EncryptMessageToGroup("Hello World 2", group.GroupID)
|
||||||
|
|
|
@ -21,6 +21,8 @@ type PublicProfile struct {
|
||||||
Trusted bool
|
Trusted bool
|
||||||
Blocked bool
|
Blocked bool
|
||||||
Onion string
|
Onion string
|
||||||
|
Attributes map[string]string
|
||||||
|
lock sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// Profile encapsulates all the attributes necessary to be a Cwtch Peer.
|
// Profile encapsulates all the attributes necessary to be a Cwtch Peer.
|
||||||
|
@ -33,6 +35,25 @@ type Profile struct {
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *PublicProfile) init() {
|
||||||
|
p.Attributes = make(map[string]string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetAttribute allows applications to store arbitrary configuration info at the profile level.
|
||||||
|
func (p *PublicProfile) SetAttribute(name string, value string) {
|
||||||
|
p.lock.Lock()
|
||||||
|
defer p.lock.Unlock()
|
||||||
|
p.Attributes[name] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAttribute returns the value of a value set with SetCustomAttribute. If no such value has been set exists is set to false.
|
||||||
|
func (p *PublicProfile) GetAttribute(name string) (value string, exists bool) {
|
||||||
|
p.lock.Lock()
|
||||||
|
defer p.lock.Unlock()
|
||||||
|
value, exists = p.Attributes[name]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
func GenerateNewProfile(name string) *Profile {
|
func GenerateNewProfile(name string) *Profile {
|
||||||
p := new(Profile)
|
p := new(Profile)
|
||||||
|
@ -63,15 +84,13 @@ func (p *Profile) GetCwtchIdentityPacket() (message []byte) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddCwtchIdentity takes a wire message and if it is a CwtchIdentity message adds the identity as a contact
|
|
||||||
// otherwise returns an error
|
|
||||||
func (p *Profile) AddCwtchIdentity(onion string, ci *protocol.CwtchIdentity) {
|
|
||||||
p.AddContact(onion, &PublicProfile{Name: ci.GetName(), Ed25519PublicKey: ci.GetEd25519PublicKey(), Onion: onion})
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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.lock.Lock()
|
||||||
|
profile.init()
|
||||||
|
// TODO: More Robust V3 Onion Handling
|
||||||
|
decodedPub, _ := base32.StdEncoding.DecodeString(strings.ToUpper(onion[:56]))
|
||||||
|
profile.Ed25519PublicKey = ed25519.PublicKey(decodedPub[:32])
|
||||||
p.Contacts[onion] = profile
|
p.Contacts[onion] = profile
|
||||||
p.lock.Unlock()
|
p.lock.Unlock()
|
||||||
}
|
}
|
||||||
|
@ -253,14 +272,13 @@ func (p *Profile) ProcessInvite(gci *protocol.GroupChatInvite, peerHostname stri
|
||||||
func (p *Profile) AddGroup(group *Group) {
|
func (p *Profile) AddGroup(group *Group) {
|
||||||
existingGroup, exists := p.Groups[group.GroupID]
|
existingGroup, exists := p.Groups[group.GroupID]
|
||||||
if !exists {
|
if !exists {
|
||||||
owner, ok := p.GetContact(group.Owner)
|
// TODO More robust error handling (confirm this onion checksum is correct)
|
||||||
if ok {
|
decodedPub, _ := base32.StdEncoding.DecodeString(strings.ToUpper(group.Owner[:56]))
|
||||||
valid := ed25519.Verify(owner.Ed25519PublicKey, []byte(group.GroupID+group.GroupServer), group.SignedGroupID)
|
valid := ed25519.Verify(ed25519.PublicKey(decodedPub[:32]), []byte(group.GroupID+group.GroupServer), group.SignedGroupID)
|
||||||
if valid {
|
if valid {
|
||||||
p.lock.Lock()
|
p.lock.Lock()
|
||||||
defer p.lock.Unlock()
|
defer p.lock.Unlock()
|
||||||
p.Groups[group.GroupID] = group
|
p.Groups[group.GroupID] = group
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else if exists && existingGroup.Owner == group.Owner {
|
} else if exists && existingGroup.Owner == group.Owner {
|
||||||
p.lock.Lock()
|
p.lock.Lock()
|
||||||
|
|
|
@ -17,8 +17,9 @@ func TestProfileIdentity(t *testing.T) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("alice should have added sarah as a contact %v", err)
|
t.Errorf("alice should have added sarah as a contact %v", err)
|
||||||
}
|
}
|
||||||
alice.AddCwtchIdentity("sarah.onion", ci.GetCwtchIdentify())
|
|
||||||
if alice.Contacts["sarah.onion"].Name != "Sarah" {
|
alice.AddContact(sarah.Onion, &sarah.PublicProfile)
|
||||||
|
if alice.Contacts[sarah.Onion].Name != "Sarah" {
|
||||||
t.Errorf("alice should have added sarah as a contact %v", alice.Contacts)
|
t.Errorf("alice should have added sarah as a contact %v", alice.Contacts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,21 +40,11 @@ func (ppc *PeerPeerConnection) GetState() ConnectionState {
|
||||||
return ppc.state
|
return ppc.state
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClientIdentity passes the given CwtchIdentity packet to the profile.
|
|
||||||
func (ppc *PeerPeerConnection) ClientIdentity(ci *protocol.CwtchIdentity) {
|
|
||||||
ppc.profile.AddCwtchIdentity(ppc.PeerHostname, ci)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandleGroupInvite passes the given group invite tothe profile
|
// HandleGroupInvite passes the given group invite tothe profile
|
||||||
func (ppc *PeerPeerConnection) HandleGroupInvite(gci *protocol.GroupChatInvite) {
|
func (ppc *PeerPeerConnection) HandleGroupInvite(gci *protocol.GroupChatInvite) {
|
||||||
ppc.profile.ProcessInvite(gci, ppc.PeerHostname)
|
ppc.profile.ProcessInvite(gci, ppc.PeerHostname)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetClientIdentityPacket returns nil to avoid peers constantly sending identity packets to eachother.
|
|
||||||
func (ppc *PeerPeerConnection) GetClientIdentityPacket() []byte {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandlePacket handles data packets on the optional data channel
|
// HandlePacket handles data packets on the optional data channel
|
||||||
func (ppc *PeerPeerConnection) HandlePacket(data []byte) []byte {
|
func (ppc *PeerPeerConnection) HandlePacket(data []byte) []byte {
|
||||||
return ppc.dataHandler(ppc.PeerHostname, data)
|
return ppc.dataHandler(ppc.PeerHostname, data)
|
||||||
|
@ -145,19 +135,6 @@ func (ppc *PeerPeerConnection) Run() error {
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
time.Sleep(time.Second * 1)
|
|
||||||
ppc.connection.Do(func() error {
|
|
||||||
channel := ppc.connection.Channel("im.cwtch.peer", channels.Outbound)
|
|
||||||
if channel != nil {
|
|
||||||
peerchannel, ok := channel.Handler.(*peer.CwtchPeerChannel)
|
|
||||||
if ok {
|
|
||||||
peerchannel.SendMessage(ppc.profile.GetCwtchIdentityPacket())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
ppc.connection.Process(ppc)
|
ppc.connection.Process(ppc)
|
||||||
|
|
|
@ -40,21 +40,6 @@ func runtestpeer(t *testing.T, tp *TestPeer, identity identity.Identity) {
|
||||||
return cpc
|
return cpc
|
||||||
})
|
})
|
||||||
|
|
||||||
go func() {
|
|
||||||
alice := model.GenerateNewProfile("alice")
|
|
||||||
time.Sleep(time.Second * 1)
|
|
||||||
rc.Do(func() error {
|
|
||||||
channel := rc.Channel("im.cwtch.peer", channels.Inbound)
|
|
||||||
if channel != nil {
|
|
||||||
peerchannel, ok := channel.Handler.(*peer.CwtchPeerChannel)
|
|
||||||
if ok {
|
|
||||||
peerchannel.SendMessage(alice.GetCwtchIdentityPacket())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}()
|
|
||||||
|
|
||||||
rc.Process(tp)
|
rc.Process(tp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -64,18 +49,10 @@ type TestPeer struct {
|
||||||
ReceivedGroupInvite bool
|
ReceivedGroupInvite bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tp *TestPeer) ClientIdentity(ci *protocol.CwtchIdentity) {
|
|
||||||
tp.ReceivedIdentityPacket = true
|
|
||||||
}
|
|
||||||
|
|
||||||
func (tp *TestPeer) HandleGroupInvite(gci *protocol.GroupChatInvite) {
|
func (tp *TestPeer) HandleGroupInvite(gci *protocol.GroupChatInvite) {
|
||||||
tp.ReceivedGroupInvite = true
|
tp.ReceivedGroupInvite = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tp *TestPeer) GetClientIdentityPacket() []byte {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestPeerPeerConnection(t *testing.T) {
|
func TestPeerPeerConnection(t *testing.T) {
|
||||||
pub, priv, _ := ed25519.GenerateKey(rand.Reader)
|
pub, priv, _ := ed25519.GenerateKey(rand.Reader)
|
||||||
identity := identity.InitializeV3("", &priv, &pub)
|
identity := identity.InitializeV3("", &priv, &pub)
|
||||||
|
@ -97,11 +74,6 @@ func TestPeerPeerConnection(t *testing.T) {
|
||||||
if state != AUTHENTICATED {
|
if state != AUTHENTICATED {
|
||||||
t.Errorf("connection state should be authenticated(3), was instead %v", state)
|
t.Errorf("connection state should be authenticated(3), was instead %v", state)
|
||||||
}
|
}
|
||||||
|
|
||||||
if tp.ReceivedIdentityPacket == false {
|
|
||||||
t.Errorf("should have received an identity packet")
|
|
||||||
}
|
|
||||||
|
|
||||||
_, invite, _ := profile.StartGroup("aaa.onion")
|
_, invite, _ := profile.StartGroup("aaa.onion")
|
||||||
ppc.SendGroupInvite(invite)
|
ppc.SendGroupInvite(invite)
|
||||||
time.Sleep(time.Second * 3)
|
time.Sleep(time.Second * 3)
|
||||||
|
|
|
@ -97,7 +97,7 @@ func TestPeerServerConnection(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if numcalls != 2 {
|
if numcalls != 2 {
|
||||||
t.Errorf("Should have received 2 calls from fetch request, instead received %v", numcalls)
|
t.Errorf("Should have received 2 calls from fetch request, instead received %v", numcalls)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -366,23 +366,12 @@ type CwtchPeerHandler struct {
|
||||||
DataHandler func(string, []byte) []byte
|
DataHandler func(string, []byte) []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClientIdentity handles incoming ClientIdentity packets
|
|
||||||
func (cph *CwtchPeerHandler) ClientIdentity(ci *protocol.CwtchIdentity) {
|
|
||||||
log.Printf("Received Client Identity from %v %v\n", cph.Onion, ci.String())
|
|
||||||
cph.Peer.Profile.AddCwtchIdentity(cph.Onion, ci)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandleGroupInvite handles incoming GroupInvites
|
// HandleGroupInvite handles incoming GroupInvites
|
||||||
func (cph *CwtchPeerHandler) HandleGroupInvite(gci *protocol.GroupChatInvite) {
|
func (cph *CwtchPeerHandler) HandleGroupInvite(gci *protocol.GroupChatInvite) {
|
||||||
log.Printf("Received GroupID from %v %v\n", cph.Onion, gci.String())
|
log.Printf("Received GroupID from %v %v\n", cph.Onion, gci.String())
|
||||||
cph.Peer.Profile.ProcessInvite(gci, cph.Onion)
|
cph.Peer.Profile.ProcessInvite(gci, cph.Onion)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetClientIdentityPacket returns our ClientIdentity packet so it can be sent to the connected peer.
|
|
||||||
func (cph *CwtchPeerHandler) GetClientIdentityPacket() []byte {
|
|
||||||
return cph.Peer.Profile.GetCwtchIdentityPacket()
|
|
||||||
}
|
|
||||||
|
|
||||||
// HandlePacket handles the Cwtch cwtchPeer Data Channel
|
// HandlePacket handles the Cwtch cwtchPeer Data Channel
|
||||||
func (cph *CwtchPeerHandler) HandlePacket(data []byte) []byte {
|
func (cph *CwtchPeerHandler) HandlePacket(data []byte) []byte {
|
||||||
return cph.DataHandler(cph.Onion, data)
|
return cph.DataHandler(cph.Onion, data)
|
||||||
|
|
|
@ -24,9 +24,7 @@ type CwtchPeerChannel struct {
|
||||||
// CwtchPeerChannelHandler is implemented by an application type to receive
|
// CwtchPeerChannelHandler is implemented by an application type to receive
|
||||||
// events from a CwtchPeerChannel.
|
// events from a CwtchPeerChannel.
|
||||||
type CwtchPeerChannelHandler interface {
|
type CwtchPeerChannelHandler interface {
|
||||||
ClientIdentity(*protocol.CwtchIdentity)
|
|
||||||
HandleGroupInvite(*protocol.GroupChatInvite)
|
HandleGroupInvite(*protocol.GroupChatInvite)
|
||||||
GetClientIdentityPacket() []byte
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SendMessage sends a raw message on this channel
|
// SendMessage sends a raw message on this channel
|
||||||
|
@ -99,13 +97,7 @@ func (cpc *CwtchPeerChannel) Packet(data []byte) {
|
||||||
cpp := &protocol.CwtchPeerPacket{}
|
cpp := &protocol.CwtchPeerPacket{}
|
||||||
err := proto.Unmarshal(data, cpp)
|
err := proto.Unmarshal(data, cpp)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
if cpp.GetCwtchIdentify() != nil {
|
if cpp.GetGroupChatInvite() != nil {
|
||||||
cpc.Handler.ClientIdentity(cpp.GetCwtchIdentify())
|
|
||||||
pkt := cpc.Handler.GetClientIdentityPacket()
|
|
||||||
if pkt != nil {
|
|
||||||
cpc.SendMessage(pkt)
|
|
||||||
}
|
|
||||||
} else if cpp.GetGroupChatInvite() != nil {
|
|
||||||
cpc.Handler.HandleGroupInvite(cpp.GetGroupChatInvite())
|
cpc.Handler.HandleGroupInvite(cpp.GetGroupChatInvite())
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -85,37 +85,18 @@ func TestPeerChannel(t *testing.T) {
|
||||||
t.Errorf("Channel should no longer be pending")
|
t.Errorf("Channel should no longer be pending")
|
||||||
}
|
}
|
||||||
|
|
||||||
gm := &protocol.CwtchIdentity{
|
|
||||||
Name: "hello",
|
|
||||||
Ed25519PublicKey: []byte{},
|
|
||||||
}
|
|
||||||
|
|
||||||
cpp := &protocol.CwtchPeerPacket{
|
|
||||||
CwtchIdentify: gm,
|
|
||||||
}
|
|
||||||
packet, _ := proto.Marshal(cpp)
|
|
||||||
cpc.Packet(packet)
|
|
||||||
if th.Received == false {
|
|
||||||
t.Errorf("Should have sent packet to handler")
|
|
||||||
}
|
|
||||||
|
|
||||||
cpc2.SendMessage(packet)
|
|
||||||
if sent == false {
|
|
||||||
t.Errorf("Should have sent packet to channel")
|
|
||||||
}
|
|
||||||
|
|
||||||
gci := &protocol.GroupChatInvite{
|
gci := &protocol.GroupChatInvite{
|
||||||
GroupName: "hello",
|
GroupName: "hello",
|
||||||
GroupSharedKey: []byte{},
|
GroupSharedKey: []byte{},
|
||||||
ServerHost: "abc.onion",
|
ServerHost: "abc.onion",
|
||||||
}
|
}
|
||||||
|
|
||||||
cpp = &protocol.CwtchPeerPacket{
|
cpp := &protocol.CwtchPeerPacket{
|
||||||
GroupChatInvite: gci,
|
GroupChatInvite: gci,
|
||||||
}
|
}
|
||||||
packet, _ = proto.Marshal(cpp)
|
packet, _ := proto.Marshal(cpp)
|
||||||
cpc.Packet(packet)
|
cpc.Packet(packet)
|
||||||
if th.ReceviedGroupInvite == false {
|
if sent && th.ReceviedGroupInvite == false {
|
||||||
t.Errorf("Should have sent invite packet to handler")
|
t.Errorf("Should have sent invite packet to handler")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue