Upgrade Dependencies + Clean up Groups #350
|
@ -69,7 +69,7 @@ func (ap *appletPeers) ListPeers() map[string]string {
|
||||||
ap.peerLock.Lock()
|
ap.peerLock.Lock()
|
||||||
defer ap.peerLock.Unlock()
|
defer ap.peerLock.Unlock()
|
||||||
for k, p := range ap.peers {
|
for k, p := range ap.peers {
|
||||||
keys[k] = p.GetName()
|
keys[k] = p.GetOnion()
|
||||||
}
|
}
|
||||||
return keys
|
return keys
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
app2 "cwtch.im/cwtch/app"
|
app2 "cwtch.im/cwtch/app"
|
||||||
|
"cwtch.im/cwtch/model/attr"
|
||||||
"cwtch.im/cwtch/peer"
|
"cwtch.im/cwtch/peer"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -12,9 +13,11 @@ import (
|
||||||
// may fill that usecase better
|
// may fill that usecase better
|
||||||
func WaitGetPeer(app app2.Application, name string) peer.CwtchPeer {
|
func WaitGetPeer(app app2.Application, name string) peer.CwtchPeer {
|
||||||
dan marked this conversation as resolved
|
|||||||
for true {
|
for true {
|
||||||
for id, n := range app.ListPeers() {
|
for id := range app.ListPeers() {
|
||||||
if n == name {
|
peer := app.GetPeer(id)
|
||||||
return app.GetPeer(id)
|
localName, _ := peer.GetAttribute(attr.GetLocalScope("name"))
|
||||||
|
if localName == name {
|
||||||
|
return peer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
|
|
|
@ -13,8 +13,6 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Event is the core struct type passed around between various subsystems. Events consist of a type which can be
|
// Event is the core struct type passed around between various subsystems. Events consist of a type which can be
|
||||||
// filtered on, an event ID for tracing and a map of Fields to string values.
|
// filtered on, an event ID for tracing and a map of Fields to string values.
|
||||||
type Event struct {
|
type Event struct {
|
||||||
|
@ -60,7 +58,7 @@ type manager struct {
|
||||||
mapMutex sync.Mutex
|
mapMutex sync.Mutex
|
||||||
internal chan bool
|
internal chan bool
|
||||||
closed bool
|
closed bool
|
||||||
trace bool
|
trace bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Manager is an interface for an event bus
|
// Manager is an interface for an event bus
|
||||||
|
@ -86,7 +84,6 @@ func (em *manager) initialize() {
|
||||||
em.internal = make(chan bool)
|
em.internal = make(chan bool)
|
||||||
em.closed = false
|
em.closed = false
|
||||||
|
|
||||||
|
|
||||||
_, em.trace = os.LookupEnv("CWTCH_EVENT_SOURCE")
|
_, em.trace = os.LookupEnv("CWTCH_EVENT_SOURCE")
|
||||||
|
|
||||||
go em.eventBus()
|
go em.eventBus()
|
||||||
|
|
4
go.mod
|
@ -3,8 +3,8 @@ module cwtch.im/cwtch
|
||||||
go 1.14
|
go 1.14
|
||||||
|
|
||||||
require (
|
require (
|
||||||
git.openprivacy.ca/cwtch.im/tapir v0.3.4
|
git.openprivacy.ca/cwtch.im/tapir v0.3.5
|
||||||
git.openprivacy.ca/openprivacy/connectivity v1.4.2
|
git.openprivacy.ca/openprivacy/connectivity v1.4.3
|
||||||
git.openprivacy.ca/openprivacy/log v1.0.2
|
git.openprivacy.ca/openprivacy/log v1.0.2
|
||||||
github.com/gtank/ristretto255 v0.1.2
|
github.com/gtank/ristretto255 v0.1.2
|
||||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||||
|
|
4
go.sum
|
@ -6,6 +6,8 @@ git.openprivacy.ca/cwtch.im/tapir v0.3.3 h1:Q7F8JijgOMMYSy3IdZl7+r6qkWckEWV1+EY7
|
||||||
git.openprivacy.ca/cwtch.im/tapir v0.3.3/go.mod h1:ZMg9Jzh0n3Os2aSF4z+bx/n8WBCJBN7KCQESXperYts=
|
git.openprivacy.ca/cwtch.im/tapir v0.3.3/go.mod h1:ZMg9Jzh0n3Os2aSF4z+bx/n8WBCJBN7KCQESXperYts=
|
||||||
git.openprivacy.ca/cwtch.im/tapir v0.3.4 h1:g7yZkfz/vWr/t2tFXa/t0Ebr/w665uIKpxpCZ3lIPCo=
|
git.openprivacy.ca/cwtch.im/tapir v0.3.4 h1:g7yZkfz/vWr/t2tFXa/t0Ebr/w665uIKpxpCZ3lIPCo=
|
||||||
git.openprivacy.ca/cwtch.im/tapir v0.3.4/go.mod h1:+Niy2AHhQC351ZTtfhC0uLjViCICyOxCJZsIlGKKNAU=
|
git.openprivacy.ca/cwtch.im/tapir v0.3.4/go.mod h1:+Niy2AHhQC351ZTtfhC0uLjViCICyOxCJZsIlGKKNAU=
|
||||||
|
git.openprivacy.ca/cwtch.im/tapir v0.3.5 h1:AlqAhluY4ivznGoHh37Khyxy0u9IbtYskP93wgtmYx8=
|
||||||
|
git.openprivacy.ca/cwtch.im/tapir v0.3.5/go.mod h1:eH6dZxXrhW0C4KZX18ksUa6XJCrEvtg8cJJ/Fy6gv+E=
|
||||||
git.openprivacy.ca/openprivacy/bine v0.0.4 h1:CO7EkGyz+jegZ4ap8g5NWRuDHA/56KKvGySR6OBPW+c=
|
git.openprivacy.ca/openprivacy/bine v0.0.4 h1:CO7EkGyz+jegZ4ap8g5NWRuDHA/56KKvGySR6OBPW+c=
|
||||||
git.openprivacy.ca/openprivacy/bine v0.0.4/go.mod h1:13ZqhKyqakDsN/ZkQkIGNULsmLyqtXc46XBcnuXm/mU=
|
git.openprivacy.ca/openprivacy/bine v0.0.4/go.mod h1:13ZqhKyqakDsN/ZkQkIGNULsmLyqtXc46XBcnuXm/mU=
|
||||||
git.openprivacy.ca/openprivacy/connectivity v1.4.0 h1:c7AANUCrlA4hIqXxIGDOWMtSe8CpDleD1877PShScbM=
|
git.openprivacy.ca/openprivacy/connectivity v1.4.0 h1:c7AANUCrlA4hIqXxIGDOWMtSe8CpDleD1877PShScbM=
|
||||||
|
@ -14,6 +16,8 @@ git.openprivacy.ca/openprivacy/connectivity v1.4.1 h1:zoM+j7PFj8mQeUCNiDNMe7Uq9d
|
||||||
git.openprivacy.ca/openprivacy/connectivity v1.4.1/go.mod h1:bR0Myx9nm2YzWtsThRelkNMV4Pp7sPDa123O1qsAbVo=
|
git.openprivacy.ca/openprivacy/connectivity v1.4.1/go.mod h1:bR0Myx9nm2YzWtsThRelkNMV4Pp7sPDa123O1qsAbVo=
|
||||||
git.openprivacy.ca/openprivacy/connectivity v1.4.2 h1:rQFIjWunLlRmXL5Efsv+7+1cA70T6Uza6RCy2PRm9zc=
|
git.openprivacy.ca/openprivacy/connectivity v1.4.2 h1:rQFIjWunLlRmXL5Efsv+7+1cA70T6Uza6RCy2PRm9zc=
|
||||||
git.openprivacy.ca/openprivacy/connectivity v1.4.2/go.mod h1:bR0Myx9nm2YzWtsThRelkNMV4Pp7sPDa123O1qsAbVo=
|
git.openprivacy.ca/openprivacy/connectivity v1.4.2/go.mod h1:bR0Myx9nm2YzWtsThRelkNMV4Pp7sPDa123O1qsAbVo=
|
||||||
|
git.openprivacy.ca/openprivacy/connectivity v1.4.3 h1:i2Ad/U9FlL9dKr2bhRck7lJ8NoWyGtoEfUwoCyMT0fU=
|
||||||
|
git.openprivacy.ca/openprivacy/connectivity v1.4.3/go.mod h1:bR0Myx9nm2YzWtsThRelkNMV4Pp7sPDa123O1qsAbVo=
|
||||||
git.openprivacy.ca/openprivacy/log v1.0.1/go.mod h1:gGYK8xHtndRLDymFtmjkG26GaMQNgyhioNS82m812Iw=
|
git.openprivacy.ca/openprivacy/log v1.0.1/go.mod h1:gGYK8xHtndRLDymFtmjkG26GaMQNgyhioNS82m812Iw=
|
||||||
git.openprivacy.ca/openprivacy/log v1.0.2 h1:HLP4wsw4ljczFAelYnbObIs821z+jgMPCe8uODPnGQM=
|
git.openprivacy.ca/openprivacy/log v1.0.2 h1:HLP4wsw4ljczFAelYnbObIs821z+jgMPCe8uODPnGQM=
|
||||||
git.openprivacy.ca/openprivacy/log v1.0.2/go.mod h1:gGYK8xHtndRLDymFtmjkG26GaMQNgyhioNS82m812Iw=
|
git.openprivacy.ca/openprivacy/log v1.0.2/go.mod h1:gGYK8xHtndRLDymFtmjkG26GaMQNgyhioNS82m812Iw=
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"cwtch.im/cwtch/model/attr"
|
"cwtch.im/cwtch/model/attr"
|
||||||
"cwtch.im/cwtch/protocol/groups"
|
"cwtch.im/cwtch/protocol/groups"
|
||||||
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -27,9 +28,7 @@ type Group struct {
|
||||||
GroupServer string
|
GroupServer string
|
||||||
Timeline Timeline `json:"-"`
|
Timeline Timeline `json:"-"`
|
||||||
Accepted bool
|
Accepted bool
|
||||||
Owner string
|
|
||||||
IsCompromised bool
|
IsCompromised bool
|
||||||
InitialMessage []byte
|
|
||||||
Attributes map[string]string
|
Attributes map[string]string
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
LocalID string
|
LocalID string
|
||||||
|
@ -63,7 +62,6 @@ func NewGroup(server string) (*Group, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
copy(group.GroupKey[:], groupKey[:])
|
copy(group.GroupKey[:], groupKey[:])
|
||||||
group.Owner = "self"
|
|
||||||
group.Attributes = make(map[string]string)
|
group.Attributes = make(map[string]string)
|
||||||
// By default we set the "name" of the group to a random string, we can override this later, but to simplify the
|
// By default we set the "name" of the group to a random string, we can override this later, but to simplify the
|
||||||
// codes around invite, we assume that this is always set.
|
// codes around invite, we assume that this is always set.
|
||||||
|
@ -82,33 +80,24 @@ func (g *Group) Compromised() {
|
||||||
g.IsCompromised = true
|
g.IsCompromised = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetInitialMessage returns the first message of the group, if one was sent with the invite.
|
|
||||||
func (g *Group) GetInitialMessage() []byte {
|
|
||||||
g.lock.Lock()
|
|
||||||
defer g.lock.Unlock()
|
|
||||||
return g.InitialMessage
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invite generates a invitation that can be sent to a cwtch peer
|
// Invite generates a invitation that can be sent to a cwtch peer
|
||||||
func (g *Group) Invite(initialMessage []byte) ([]byte, error) {
|
func (g *Group) Invite() (string, error) {
|
||||||
|
|
||||||
if g.SignedGroupID == nil {
|
if g.SignedGroupID == nil {
|
||||||
return nil, errors.New("group isn't signed")
|
return "", errors.New("group isn't signed")
|
||||||
}
|
}
|
||||||
|
|
||||||
g.InitialMessage = initialMessage[:]
|
|
||||||
|
|
||||||
gci := &groups.GroupInvite{
|
gci := &groups.GroupInvite{
|
||||||
GroupID: g.GroupID,
|
GroupID: g.GroupID,
|
||||||
GroupName: g.Attributes[attr.GetLocalScope("name")],
|
GroupName: g.Attributes[attr.GetLocalScope("name")],
|
||||||
SharedKey: g.GroupKey[:],
|
SharedKey: g.GroupKey[:],
|
||||||
ServerHost: g.GroupServer,
|
ServerHost: g.GroupServer,
|
||||||
SignedGroupID: g.SignedGroupID[:],
|
SignedGroupID: g.SignedGroupID[:],
|
||||||
InitialMessage: initialMessage[:],
|
|
||||||
}
|
}
|
||||||
|
|
||||||
invite, err := json.Marshal(gci)
|
invite, err := json.Marshal(gci)
|
||||||
return invite, err
|
serializedInvite := fmt.Sprintf("torv3%v", base64.StdEncoding.EncodeToString(invite))
|
||||||
|
return serializedInvite, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddSentMessage takes a DecryptedGroupMessage and adds it to the Groups Timeline
|
// AddSentMessage takes a DecryptedGroupMessage and adds it to the Groups Timeline
|
||||||
|
|
|
@ -16,7 +16,7 @@ func TestMessagePadding(t *testing.T) {
|
||||||
|
|
||||||
gid, invite, _ := alice.StartGroup("2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd")
|
gid, invite, _ := alice.StartGroup("2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd")
|
||||||
|
|
||||||
sarah.ProcessInvite(string(invite), alice.Onion)
|
sarah.ProcessInvite(invite)
|
||||||
|
|
||||||
group := alice.GetGroup(gid)
|
group := alice.GetGroup(gid)
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ func TestTranscriptConsistency(t *testing.T) {
|
||||||
|
|
||||||
gid, invite, _ := alice.StartGroup("2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd")
|
gid, invite, _ := alice.StartGroup("2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd")
|
||||||
|
|
||||||
sarah.ProcessInvite(string(invite), alice.Onion)
|
sarah.ProcessInvite(invite)
|
||||||
|
|
||||||
group := alice.GetGroup(gid)
|
group := alice.GetGroup(gid)
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"cwtch.im/cwtch/protocol/groups"
|
"cwtch.im/cwtch/protocol/groups"
|
||||||
"encoding/base32"
|
"encoding/base32"
|
||||||
|
"encoding/base64"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
@ -333,22 +334,15 @@ func (p *Profile) SignMessage(message string) []byte {
|
||||||
|
|
||||||
// StartGroup when given a server, creates a new Group under this profile and returns the group id an a precomputed
|
// StartGroup when given a server, creates a new Group under this profile and returns the group id an a precomputed
|
||||||
// invite which can be sent on the wire.
|
// invite which can be sent on the wire.
|
||||||
func (p *Profile) StartGroup(server string) (groupID string, invite []byte, err error) {
|
func (p *Profile) StartGroup(server string) (groupID string, invite string, err error) {
|
||||||
return p.StartGroupWithMessage(server, []byte{})
|
|
||||||
}
|
|
||||||
|
|
||||||
// StartGroupWithMessage when given a server, and an initial message creates a new Group under this profile and returns the group id an a precomputed
|
|
||||||
// invite which can be sent on the wire.
|
|
||||||
func (p *Profile) StartGroupWithMessage(server string, initialMessage []byte) (groupID string, invite []byte, err error) {
|
|
||||||
group, err := NewGroup(server)
|
group, err := NewGroup(server)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", nil, err
|
return "", "", err
|
||||||
}
|
}
|
||||||
groupID = group.GroupID
|
groupID = group.GroupID
|
||||||
group.Owner = p.Onion
|
|
||||||
signedGroupID := p.SignMessage(groupID + server)
|
signedGroupID := p.SignMessage(groupID + server)
|
||||||
group.SignGroup(signedGroupID)
|
group.SignGroup(signedGroupID)
|
||||||
invite, err = group.Invite(initialMessage)
|
invite, err = group.Invite()
|
||||||
p.lock.Lock()
|
p.lock.Lock()
|
||||||
defer p.lock.Unlock()
|
defer p.lock.Unlock()
|
||||||
p.Groups[group.GroupID] = group
|
p.Groups[group.GroupID] = group
|
||||||
|
@ -364,33 +358,36 @@ func (p *Profile) GetGroup(groupID string) (g *Group) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessInvite adds a new group invite to the profile. returns the new group ID
|
// ProcessInvite adds a new group invite to the profile. returns the new group ID
|
||||||
func (p *Profile) ProcessInvite(invite string, peerHostname string) (string, string, error) {
|
func (p *Profile) ProcessInvite(invite string) (string, error) {
|
||||||
var gci groups.GroupInvite
|
if strings.HasPrefix(invite, "torv3") {
|
||||||
err := json.Unmarshal([]byte(invite), &gci)
|
data, err := base64.StdEncoding.DecodeString(invite[5:])
|
||||||
if err == nil {
|
if err == nil {
|
||||||
group := new(Group)
|
var gci groups.GroupInvite
|
||||||
group.Version = CurrentGroupVersion
|
err := json.Unmarshal(data, &gci)
|
||||||
group.GroupID = gci.GroupID
|
if err == nil {
|
||||||
group.LocalID = GenerateRandomID()
|
group := new(Group)
|
||||||
group.SignedGroupID = gci.SignedGroupID
|
group.Version = CurrentGroupVersion
|
||||||
copy(group.GroupKey[:], gci.SharedKey[:])
|
group.GroupID = gci.GroupID
|
||||||
group.GroupServer = gci.ServerHost
|
group.LocalID = GenerateRandomID()
|
||||||
group.InitialMessage = []byte(gci.InitialMessage)
|
group.SignedGroupID = gci.SignedGroupID
|
||||||
group.Accepted = false
|
copy(group.GroupKey[:], gci.SharedKey[:])
|
||||||
group.Owner = peerHostname
|
group.GroupServer = gci.ServerHost
|
||||||
group.Attributes = make(map[string]string)
|
group.Accepted = false
|
||||||
p.AddGroup(group)
|
group.Attributes = make(map[string]string)
|
||||||
return group.GroupID, gci.GroupName, nil
|
p.AddGroup(group)
|
||||||
|
return group.GroupID, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return "", "", err
|
return "", errors.New("unsupported exported group type")
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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()
|
||||||
|
defer p.lock.Unlock()
|
||||||
_, exists := p.Groups[group.GroupID]
|
_, exists := p.Groups[group.GroupID]
|
||||||
if !exists {
|
if !exists {
|
||||||
p.lock.Lock()
|
|
||||||
defer p.lock.Unlock()
|
|
||||||
p.Groups[group.GroupID] = group
|
p.Groups[group.GroupID] = group
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,7 +64,7 @@ func TestRejectGroupInvite(t *testing.T) {
|
||||||
alice.AddContact(sarah.Onion, &sarah.PublicProfile)
|
alice.AddContact(sarah.Onion, &sarah.PublicProfile)
|
||||||
|
|
||||||
gid, invite, _ := alice.StartGroup("2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd")
|
gid, invite, _ := alice.StartGroup("2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd")
|
||||||
sarah.ProcessInvite(string(invite), alice.Onion)
|
sarah.ProcessInvite(invite)
|
||||||
group := alice.GetGroup(gid)
|
group := alice.GetGroup(gid)
|
||||||
if len(sarah.Groups) == 1 {
|
if len(sarah.Groups) == 1 {
|
||||||
if sarah.GetGroup(group.GroupID).Accepted {
|
if sarah.GetGroup(group.GroupID).Accepted {
|
||||||
|
@ -85,8 +85,8 @@ func TestProfileGroup(t *testing.T) {
|
||||||
sarah.AddContact(alice.Onion, &alice.PublicProfile)
|
sarah.AddContact(alice.Onion, &alice.PublicProfile)
|
||||||
alice.AddContact(sarah.Onion, &sarah.PublicProfile)
|
alice.AddContact(sarah.Onion, &sarah.PublicProfile)
|
||||||
|
|
||||||
gid, invite, _ := alice.StartGroupWithMessage("2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd", []byte("Hello World"))
|
gid, invite, _ := alice.StartGroup("2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd")
|
||||||
sarah.ProcessInvite(string(invite), alice.Onion)
|
sarah.ProcessInvite(invite)
|
||||||
if len(sarah.GetGroups()) != 1 {
|
if len(sarah.GetGroups()) != 1 {
|
||||||
t.Errorf("sarah should only be in 1 group instead: %v", sarah.GetGroups())
|
t.Errorf("sarah should only be in 1 group instead: %v", sarah.GetGroups())
|
||||||
}
|
}
|
||||||
|
@ -97,17 +97,11 @@ func TestProfileGroup(t *testing.T) {
|
||||||
alice.AttemptDecryption(c, s1)
|
alice.AttemptDecryption(c, s1)
|
||||||
|
|
||||||
gid2, invite2, _ := alice.StartGroup("2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd")
|
gid2, invite2, _ := alice.StartGroup("2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd")
|
||||||
sarah.ProcessInvite(string(invite2), alice.Onion)
|
sarah.ProcessInvite(invite2)
|
||||||
group2 := alice.GetGroup(gid2)
|
group2 := alice.GetGroup(gid2)
|
||||||
c2, s2, _ := sarah.EncryptMessageToGroup("Hello World", group2.GroupID)
|
c2, s2, _ := sarah.EncryptMessageToGroup("Hello World", group2.GroupID)
|
||||||
alice.AttemptDecryption(c2, s2)
|
alice.AttemptDecryption(c2, s2)
|
||||||
|
|
||||||
sarahGroup := sarah.GetGroup(group.GroupID)
|
|
||||||
im := sarahGroup.GetInitialMessage()
|
|
||||||
if string(im) != "Hello World" {
|
|
||||||
t.Errorf("Initial Message was not stored properly: %v", im)
|
|
||||||
}
|
|
||||||
|
|
||||||
_, _, err := sarah.EncryptMessageToGroup(string(make([]byte, MaxGroupMessageLength*2)), group2.GroupID)
|
_, _, err := sarah.EncryptMessageToGroup(string(make([]byte, MaxGroupMessageLength*2)), group2.GroupID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("Overly long message should have returned an error")
|
t.Errorf("Overly long message should have returned an error")
|
||||||
|
@ -115,7 +109,7 @@ func TestProfileGroup(t *testing.T) {
|
||||||
|
|
||||||
bob := GenerateNewProfile("bob")
|
bob := GenerateNewProfile("bob")
|
||||||
bob.AddContact(alice.Onion, &alice.PublicProfile)
|
bob.AddContact(alice.Onion, &alice.PublicProfile)
|
||||||
bob.ProcessInvite(string(invite2), alice.Onion)
|
bob.ProcessInvite(invite2)
|
||||||
c3, s3, err := bob.EncryptMessageToGroup("Bobs Message", group2.GroupID)
|
c3, s3, err := bob.EncryptMessageToGroup("Bobs Message", group2.GroupID)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
ok, _, message, _ := alice.AttemptDecryption(c3, s3)
|
ok, _, message, _ := alice.AttemptDecryption(c3, s3)
|
||||||
|
|
|
@ -109,8 +109,8 @@ type ReadGroups interface {
|
||||||
|
|
||||||
// ModifyGroups provides write-only access add/edit/remove new groups
|
// ModifyGroups provides write-only access add/edit/remove new groups
|
||||||
type ModifyGroups interface {
|
type ModifyGroups interface {
|
||||||
ImportGroup(string) error
|
ImportGroup(string) (string, error)
|
||||||
StartGroup(string) (string, []byte, error)
|
StartGroup(string) (string, string, error)
|
||||||
AcceptInvite(string) error
|
AcceptInvite(string) error
|
||||||
RejectInvite(string)
|
RejectInvite(string)
|
||||||
DeleteGroup(string)
|
DeleteGroup(string)
|
||||||
|
@ -172,14 +172,6 @@ type CwtchPeer interface {
|
||||||
|
|
||||||
SendMessages
|
SendMessages
|
||||||
SendMessagesToGroup
|
SendMessagesToGroup
|
||||||
|
|
||||||
// Deprecated
|
|
||||||
// TODO Should be removed
|
|
||||||
GetName() string
|
|
||||||
SetName(string)
|
|
||||||
|
|
||||||
// TODO Should not be exposed...
|
|
||||||
ProcessInvite(string, string) (string, string, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCwtchPeer creates and returns a new cwtchPeer with the given name.
|
// NewCwtchPeer creates and returns a new cwtchPeer with the given name.
|
||||||
|
@ -223,20 +215,16 @@ func (cp *cwtchPeer) AutoHandleEvents(events []event.Type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ImportGroup initializes a group from an imported source rather than a peer invite
|
// ImportGroup initializes a group from an imported source rather than a peer invite
|
||||||
func (cp *cwtchPeer) ImportGroup(exportedInvite string) (err error) {
|
func (cp *cwtchPeer) ImportGroup(exportedInvite string) (string, error) {
|
||||||
if strings.HasPrefix(exportedInvite, "torv3") {
|
cp.mutex.Lock()
|
||||||
data, err := base64.StdEncoding.DecodeString(exportedInvite[5:])
|
defer cp.mutex.Unlock()
|
||||||
if err == nil {
|
gid, err := cp.Profile.ProcessInvite(exportedInvite)
|
||||||
cp.eventBus.Publish(event.NewEvent(event.NewGroupInvite, map[event.Field]string{
|
|
||||||
event.GroupInvite: string(data),
|
if err == nil {
|
||||||
event.Imported: "true",
|
cp.eventBus.Publish(event.NewEvent(event.NewGroup, map[event.Field]string{event.GroupID: gid, event.GroupInvite: exportedInvite}))
|
||||||
}))
|
|
||||||
} else {
|
|
||||||
log.Errorf("error decoding group invite: %v", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
return errors.New("unsupported exported group type")
|
|
||||||
|
return gid, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExportGroup serializes a group invite so it can be given offline
|
// ExportGroup serializes a group invite so it can be given offline
|
||||||
|
@ -245,24 +233,15 @@ func (cp *cwtchPeer) ExportGroup(groupID string) (string, error) {
|
||||||
defer cp.mutex.Unlock()
|
defer cp.mutex.Unlock()
|
||||||
group := cp.Profile.GetGroup(groupID)
|
group := cp.Profile.GetGroup(groupID)
|
||||||
if group != nil {
|
if group != nil {
|
||||||
invite, err := group.Invite(group.GetInitialMessage())
|
return group.Invite()
|
||||||
if err == nil {
|
|
||||||
exportedInvite := "torv3" + base64.StdEncoding.EncodeToString(invite)
|
|
||||||
return exportedInvite, err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return "", errors.New("group id could not be found")
|
return "", errors.New("group id could not be found")
|
||||||
}
|
}
|
||||||
|
|
||||||
// StartGroup create a new group linked to the given server and returns the group ID, an invite or an error.
|
// StartGroup create a new group linked to the given server and returns the group ID, an invite or an error.
|
||||||
func (cp *cwtchPeer) StartGroup(server string) (string, []byte, error) {
|
func (cp *cwtchPeer) StartGroup(server string) (string, string, error) {
|
||||||
return cp.StartGroupWithMessage(server, []byte{})
|
|
||||||
}
|
|
||||||
|
|
||||||
// StartGroupWithMessage create a new group linked to the given server and returns the group ID, an invite or an error.
|
|
||||||
func (cp *cwtchPeer) StartGroupWithMessage(server string, initialMessage []byte) (groupID string, invite []byte, err error) {
|
|
||||||
cp.mutex.Lock()
|
cp.mutex.Lock()
|
||||||
groupID, invite, err = cp.Profile.StartGroupWithMessage(server, initialMessage)
|
groupID, invite, err := cp.Profile.StartGroup(server)
|
||||||
cp.mutex.Unlock()
|
cp.mutex.Unlock()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
group := cp.GetGroup(groupID)
|
group := cp.GetGroup(groupID)
|
||||||
|
@ -275,7 +254,7 @@ func (cp *cwtchPeer) StartGroupWithMessage(server string, initialMessage []byte)
|
||||||
} else {
|
} else {
|
||||||
log.Errorf("error creating group: %v", err)
|
log.Errorf("error creating group: %v", err)
|
||||||
}
|
}
|
||||||
return
|
return groupID, invite, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetGroups returns an unordered list of all group IDs.
|
// GetGroups returns an unordered list of all group IDs.
|
||||||
|
@ -400,18 +379,6 @@ func (cp *cwtchPeer) GetContact(onion string) *model.PublicProfile {
|
||||||
return contact
|
return contact
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cp *cwtchPeer) GetName() string {
|
|
||||||
cp.mutex.Lock()
|
|
||||||
defer cp.mutex.Unlock()
|
|
||||||
return cp.Profile.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cp *cwtchPeer) SetName(newName string) {
|
|
||||||
cp.mutex.Lock()
|
|
||||||
defer cp.mutex.Unlock()
|
|
||||||
cp.Profile.Name = newName
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cp *cwtchPeer) GetOnion() string {
|
func (cp *cwtchPeer) GetOnion() string {
|
||||||
cp.mutex.Lock()
|
cp.mutex.Lock()
|
||||||
defer cp.mutex.Unlock()
|
defer cp.mutex.Unlock()
|
||||||
|
@ -465,14 +432,14 @@ func (cp *cwtchPeer) DeleteGroup(groupID string) {
|
||||||
func (cp *cwtchPeer) InviteOnionToGroup(onion string, groupid string) error {
|
func (cp *cwtchPeer) InviteOnionToGroup(onion string, groupid string) error {
|
||||||
cp.mutex.Lock()
|
cp.mutex.Lock()
|
||||||
group := cp.Profile.GetGroup(groupid)
|
group := cp.Profile.GetGroup(groupid)
|
||||||
defer cp.mutex.Unlock()
|
|
||||||
if group == nil {
|
if group == nil {
|
||||||
|
cp.mutex.Unlock()
|
||||||
return errors.New("invalid group id")
|
return errors.New("invalid group id")
|
||||||
}
|
}
|
||||||
|
invite, err := group.Invite()
|
||||||
invite, err := group.Invite(group.InitialMessage)
|
cp.mutex.Unlock()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
cp.eventBus.Publish(event.NewEvent(event.InvitePeerToGroup, map[event.Field]string{event.RemotePeer: onion, event.GroupInvite: string(invite)}))
|
cp.SendMessageToPeer(onion, invite)
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -537,13 +504,6 @@ func (cp *cwtchPeer) SetContactAuthorization(peer string, authorization model.Au
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProcessInvite adds a new group invite to the profile. returns the new group ID
|
|
||||||
func (cp *cwtchPeer) ProcessInvite(invite string, remotePeer string) (string, string, error) {
|
|
||||||
cp.mutex.Lock()
|
|
||||||
defer cp.mutex.Unlock()
|
|
||||||
return cp.Profile.ProcessInvite(invite, remotePeer)
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 {
|
||||||
cp.mutex.Lock()
|
cp.mutex.Lock()
|
||||||
|
@ -615,6 +575,11 @@ func (cp *cwtchPeer) GetAttribute(key string) (string, bool) {
|
||||||
if val, exists := cp.Profile.GetAttribute(key); exists {
|
if val, exists := cp.Profile.GetAttribute(key); exists {
|
||||||
return val, true
|
return val, true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if key == attr.GetLocalScope("name") {
|
||||||
dan marked this conversation as resolved
dan
commented
wait, why this? why not using the attribute map like all others? do you have a paired override for setAttribute? which also we prolly shouldn't do? I thougt we were just gonna delete Profile.Name wait, why this? why not using the attribute map like all others?
do you have a paired override for setAttribute? which also we prolly shouldn't do? I thougt we were just gonna delete Profile.Name
sarah
commented
this code will use default to set attribute first..this is a fallback for the case where we create a profile (which is prior to InitForEvents) and then immediately try to look it up (like in the integration test)...we don't yet have any way to alert the storage engine to save name as an attribute. At some point we should reconcile this - probably by removing Name from profile, and any reference in App(Client/Server) - but that is a bigger change that touches a lot more of the integration test and app so I felt this was a good compromise that removes the troublesome APIs while preserving the speciality of Name until we have the time to redo Application to not rely on it. this code will use default to set attribute first..this is a fallback for the case where we create a profile (which is prior to InitForEvents) and then immediately try to look it up (like in the integration test)...we don't yet have any way to alert the storage engine to save name as an attribute.
At some point we should reconcile this - probably by removing Name from profile, and any reference in App(Client/Server) - but that is a bigger change that touches a lot more of the integration test and app so I felt this was a good compromise that removes the troublesome APIs while preserving the speciality of Name until we have the time to redo Application to not rely on it.
dan
commented
ah i see, I missed its a fall through if we didnt get the attribute which we check first! ah i see, I missed its a fall through if we didnt get the attribute which we check first!
yeah the UI has all that code around name getting and falling back to onion but yeah putting it here is prolly wrong. ok thats fine
|
|||||||
|
return cp.Profile.Name, true
|
||||||
|
}
|
||||||
|
|
||||||
return "", false
|
return "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -772,23 +737,6 @@ func (cp *cwtchPeer) eventHandler() {
|
||||||
cp.SetContactAttribute(onion, attr.GetPeerScope(path), val)
|
cp.SetContactAttribute(onion, attr.GetPeerScope(path), val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case event.NewGroupInvite:
|
|
||||||
cp.mutex.Lock()
|
|
||||||
group, groupName, err := cp.Profile.ProcessInvite(ev.Data[event.GroupInvite], ev.Data[event.RemotePeer])
|
|
||||||
if err == nil {
|
|
||||||
if ev.Data[event.Imported] == "true" {
|
|
||||||
cp.Profile.GetGroup(group).Accepted = true
|
|
||||||
cp.mutex.Unlock() // TODO...seriously need a better way of handling these cases
|
|
||||||
cp.SetGroupAttribute(group, attr.GetLocalScope("name"), groupName)
|
|
||||||
err = cp.JoinServer(cp.Profile.GetGroup(group).GroupServer)
|
|
||||||
cp.mutex.Lock()
|
|
||||||
if err != nil {
|
|
||||||
log.Errorf("Joining Server should have worked %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cp.eventBus.Publish(event.NewEvent(event.NewGroup, map[event.Field]string{event.GroupID: group}))
|
|
||||||
}
|
|
||||||
cp.mutex.Unlock()
|
|
||||||
case event.PeerStateChange:
|
case event.PeerStateChange:
|
||||||
cp.mutex.Lock()
|
cp.mutex.Lock()
|
||||||
if _, exists := cp.Profile.Contacts[ev.Data[event.RemotePeer]]; exists {
|
if _, exists := cp.Profile.Contacts[ev.Data[event.RemotePeer]]; exists {
|
||||||
|
|
|
@ -468,9 +468,7 @@ func (e *engine) sendMessageToGroup(server string, ct []byte, sig []byte) error
|
||||||
|
|
||||||
func (e *engine) handlePeerMessage(hostname string, eventID string, context string, message []byte) {
|
func (e *engine) handlePeerMessage(hostname string, eventID string, context string, message []byte) {
|
||||||
log.Debugf("New message from peer: %v %v", hostname, context)
|
log.Debugf("New message from peer: %v %v", hostname, context)
|
||||||
if context == event.ContextInvite {
|
if context == event.ContextGetVal {
|
||||||
e.eventManager.Publish(event.NewEvent(event.NewGroupInvite, map[event.Field]string{event.TimestampReceived: time.Now().Format(time.RFC3339Nano), event.RemotePeer: hostname, event.GroupInvite: string(message)}))
|
|
||||||
} else if context == event.ContextGetVal {
|
|
||||||
var getVal peerGetVal
|
var getVal peerGetVal
|
||||||
err := json.Unmarshal(message, &getVal)
|
err := json.Unmarshal(message, &getVal)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
package groups
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/rand"
|
|
||||||
"cwtch.im/cwtch/model"
|
|
||||||
"golang.org/x/crypto/nacl/secretbox"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Fuzz various group related functions
|
|
||||||
func Fuzz(data []byte) int {
|
|
||||||
profile := model.GenerateNewProfile("fuzz")
|
|
||||||
inviteid, _, err := profile.ProcessInvite(string(data), profile.Onion)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
if inviteid != "" {
|
|
||||||
panic("should not have added a group on err")
|
|
||||||
}
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
id, _, _ := profile.StartGroup("2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd")
|
|
||||||
var nonce [24]byte
|
|
||||||
io.ReadFull(rand.Reader, nonce[:])
|
|
||||||
encrypted := secretbox.Seal(nonce[:], data, &nonce, &profile.GetGroup(id).GroupKey)
|
|
||||||
|
|
||||||
ok, _, _, _ := profile.AttemptDecryption(encrypted, data)
|
|
||||||
if ok {
|
|
||||||
panic("this probably shouldn't happen")
|
|
||||||
}
|
|
||||||
ok = profile.VerifyGroupMessage(string(data), string(data), string(data), 0, encrypted, data)
|
|
||||||
if ok {
|
|
||||||
panic("this probably shouldn't happen")
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
package invites
|
|
||||||
|
|
||||||
import (
|
|
||||||
"cwtch.im/cwtch/event"
|
|
||||||
"cwtch.im/cwtch/peer"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Fuzz import group function
|
|
||||||
func Fuzz(data []byte) int {
|
|
||||||
peer := peer.NewCwtchPeer("fuzz")
|
|
||||||
peer.Init(event.NewEventManager())
|
|
||||||
err := peer.ImportGroup(string(data))
|
|
||||||
if err != nil {
|
|
||||||
if len(peer.GetGroups()) > 0 {
|
|
||||||
panic("group added despite error")
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return 1
|
|
||||||
}
|
|
|
@ -11,13 +11,12 @@ const CwtchServerSyncedCapability = tapir.Capability("CwtchServerSyncedCapabilit
|
||||||
|
|
||||||
// GroupInvite provides a structured type for communicating group information to peers
|
// GroupInvite provides a structured type for communicating group information to peers
|
||||||
type GroupInvite struct {
|
type GroupInvite struct {
|
||||||
GroupID string
|
GroupID string
|
||||||
GroupName string
|
GroupName string
|
||||||
SignedGroupID []byte
|
SignedGroupID []byte
|
||||||
Timestamp uint64
|
Timestamp uint64
|
||||||
SharedKey []byte
|
SharedKey []byte
|
||||||
ServerHost string
|
ServerHost string
|
||||||
InitialMessage []byte
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DecryptedGroupMessage is the main encapsulation of group message data
|
// DecryptedGroupMessage is the main encapsulation of group message data
|
||||||
|
|
|
@ -21,6 +21,7 @@ const (
|
||||||
func main() {
|
func main() {
|
||||||
log.AddEverythingFromPattern("server/app/main")
|
log.AddEverythingFromPattern("server/app/main")
|
||||||
log.AddEverythingFromPattern("server/server")
|
log.AddEverythingFromPattern("server/server")
|
||||||
|
log.SetLevel(log.LevelDebug)
|
||||||
configDir := os.Getenv("CWTCH_CONFIG_DIR")
|
configDir := os.Getenv("CWTCH_CONFIG_DIR")
|
||||||
|
|
||||||
if len(os.Args) == 2 && os.Args[1] == "gen1" {
|
if len(os.Args) == 2 && os.Args[1] == "gen1" {
|
||||||
|
@ -73,14 +74,17 @@ func main() {
|
||||||
// TODO create a random group for testing
|
// TODO create a random group for testing
|
||||||
group, _ := model.NewGroup(tor.GetTorV3Hostname(serverConfig.PublicKey))
|
group, _ := model.NewGroup(tor.GetTorV3Hostname(serverConfig.PublicKey))
|
||||||
group.SignGroup([]byte{})
|
group.SignGroup([]byte{})
|
||||||
invite, err := group.Invite([]byte{})
|
invite, err := group.Invite()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
fmt.Printf("%v\n", "torv3"+base64.StdEncoding.EncodeToString(invite))
|
fmt.Printf("Invite: %v", invite)
|
||||||
|
|
||||||
bundle := server.KeyBundle().Serialize()
|
bundle := server.KeyBundle().Serialize()
|
||||||
log.Infof("Server Config: server:%s", base64.StdEncoding.EncodeToString(bundle))
|
log.Infof("Server Config: server:%s", base64.StdEncoding.EncodeToString(bundle))
|
||||||
|
|
||||||
|
log.Infof("Server Tofu Bundle: tofubundle:server:%s||%s", base64.StdEncoding.EncodeToString(bundle), invite)
|
||||||
|
|
||||||
server.Run(acn)
|
server.Run(acn)
|
||||||
for {
|
for {
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
|
|
|
@ -39,7 +39,7 @@ type Server struct {
|
||||||
func (s *Server) Setup(serverConfig Config) {
|
func (s *Server) Setup(serverConfig Config) {
|
||||||
s.config = serverConfig
|
s.config = serverConfig
|
||||||
bs := new(persistence.BoltPersistence)
|
bs := new(persistence.BoltPersistence)
|
||||||
bs.Open(path.Join(serverConfig.ConfigDir, "tokens.db"))
|
bs.Open(path.Join(serverConfig.ConfigDir, "tokens1.db"))
|
||||||
s.tokenServer = privacypass.NewTokenServerFromStore(bs)
|
s.tokenServer = privacypass.NewTokenServerFromStore(bs)
|
||||||
s.tokenService = s.config.TokenServiceIdentity()
|
s.tokenService = s.config.TokenServiceIdentity()
|
||||||
s.tokenServicePrivKey = s.config.TokenServerPrivateKey
|
s.tokenServicePrivKey = s.config.TokenServerPrivateKey
|
||||||
|
|
|
@ -42,7 +42,7 @@ func TestProfileStoreUpgradeV0toV1(t *testing.T) {
|
||||||
t.Errorf("Creating group invite: %v\n", err)
|
t.Errorf("Creating group invite: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ps1.AddGroup(invite, profile.Onion)
|
ps1.AddGroup(invite)
|
||||||
|
|
||||||
fmt.Println("Sending 200 messages...")
|
fmt.Println("Sending 200 messages...")
|
||||||
|
|
||||||
|
|
|
@ -53,8 +53,8 @@ func ReadProfile(directory, password string) (*model.Profile, error) {
|
||||||
/********************************************************************************************/
|
/********************************************************************************************/
|
||||||
|
|
||||||
// AddGroup For testing, adds a group to the profile (and starts a stream store)
|
// AddGroup For testing, adds a group to the profile (and starts a stream store)
|
||||||
func (ps *ProfileStoreV0) AddGroup(invite []byte, peer string) {
|
func (ps *ProfileStoreV0) AddGroup(invite string) {
|
||||||
gid, _, err := ps.profile.ProcessInvite(string(invite), peer)
|
gid, err := ps.profile.ProcessInvite(invite)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
ps.save()
|
ps.save()
|
||||||
group := ps.profile.Groups[gid]
|
group := ps.profile.Groups[gid]
|
||||||
|
|
|
@ -40,7 +40,7 @@ func TestProfileStoreWriteRead(t *testing.T) {
|
||||||
t.Errorf("Creating group invite: %v\n", err)
|
t.Errorf("Creating group invite: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ps1.AddGroup(invite, profile.Onion)
|
ps1.AddGroup(invite)
|
||||||
|
|
||||||
ps1.AddGroupMessage(groupid, time.Now().Format(time.RFC3339Nano), time.Now().Format(time.RFC3339Nano), ps1.getProfileCopy(true).Onion, testMessage)
|
ps1.AddGroupMessage(groupid, time.Now().Format(time.RFC3339Nano), time.Now().Format(time.RFC3339Nano), ps1.getProfileCopy(true).Onion, testMessage)
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,7 @@ func (ps *ProfileStoreV1) initProfileWriterStore() {
|
||||||
ps.eventManager.Subscribe(event.SetGroupAttribute, ps.queue)
|
ps.eventManager.Subscribe(event.SetGroupAttribute, ps.queue)
|
||||||
ps.eventManager.Subscribe(event.AcceptGroupInvite, ps.queue)
|
ps.eventManager.Subscribe(event.AcceptGroupInvite, ps.queue)
|
||||||
ps.eventManager.Subscribe(event.RejectGroupInvite, ps.queue)
|
ps.eventManager.Subscribe(event.RejectGroupInvite, ps.queue)
|
||||||
ps.eventManager.Subscribe(event.NewGroupInvite, ps.queue)
|
ps.eventManager.Subscribe(event.NewGroup, ps.queue)
|
||||||
ps.eventManager.Subscribe(event.NewMessageFromGroup, ps.queue)
|
ps.eventManager.Subscribe(event.NewMessageFromGroup, ps.queue)
|
||||||
ps.eventManager.Subscribe(event.SendMessageToPeer, ps.queue)
|
ps.eventManager.Subscribe(event.SendMessageToPeer, ps.queue)
|
||||||
ps.eventManager.Subscribe(event.PeerAcknowledgement, ps.queue)
|
ps.eventManager.Subscribe(event.PeerAcknowledgement, ps.queue)
|
||||||
|
@ -377,8 +377,8 @@ func (ps *ProfileStoreV1) eventHandler() {
|
||||||
case event.RejectGroupInvite:
|
case event.RejectGroupInvite:
|
||||||
ps.profile.RejectInvite(ev.Data[event.GroupID])
|
ps.profile.RejectInvite(ev.Data[event.GroupID])
|
||||||
ps.save()
|
ps.save()
|
||||||
case event.NewGroupInvite:
|
case event.NewGroup:
|
||||||
gid, _, err := ps.profile.ProcessInvite(ev.Data[event.GroupInvite], ev.Data[event.RemotePeer])
|
gid, err := ps.profile.ProcessInvite(ev.Data[event.GroupInvite])
|
||||||
if err == nil {
|
if err == nil {
|
||||||
ps.save()
|
ps.save()
|
||||||
group := ps.profile.Groups[gid]
|
group := ps.profile.Groups[gid]
|
||||||
|
|
|
@ -35,7 +35,7 @@ func TestProfileStoreWriteRead(t *testing.T) {
|
||||||
t.Errorf("Creating group invite: %v\n", err)
|
t.Errorf("Creating group invite: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
eventBus.Publish(event.NewEvent(event.NewGroupInvite, map[event.Field]string{event.TimestampReceived: time.Now().Format(time.RFC3339Nano), event.RemotePeer: ps1.GetProfileCopy(true).Onion, event.GroupInvite: string(invite)}))
|
eventBus.Publish(event.NewEvent(event.NewGroup, map[event.Field]string{event.TimestampReceived: time.Now().Format(time.RFC3339Nano), event.RemotePeer: ps1.GetProfileCopy(true).Onion, event.GroupInvite: string(invite)}))
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
eventBus.Publish(event.NewEvent(event.NewMessageFromGroup, map[event.Field]string{
|
eventBus.Publish(event.NewEvent(event.NewMessageFromGroup, map[event.Field]string{
|
||||||
|
@ -89,7 +89,7 @@ func TestProfileStoreChangePassword(t *testing.T) {
|
||||||
t.Errorf("Creating group invite: %v\n", err)
|
t.Errorf("Creating group invite: %v\n", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
eventBus.Publish(event.NewEvent(event.NewGroupInvite, map[event.Field]string{event.TimestampReceived: time.Now().Format(time.RFC3339Nano), event.RemotePeer: ps1.GetProfileCopy(true).Onion, event.GroupInvite: string(invite)}))
|
eventBus.Publish(event.NewEvent(event.NewGroup, map[event.Field]string{event.TimestampReceived: time.Now().Format(time.RFC3339Nano), event.RemotePeer: ps1.GetProfileCopy(true).Onion, event.GroupInvite: string(invite)}))
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
fmt.Println("Sending 200 messages...")
|
fmt.Println("Sending 200 messages...")
|
||||||
|
|
|
@ -23,6 +23,7 @@ import (
|
||||||
"path"
|
"path"
|
||||||
"runtime"
|
"runtime"
|
||||||
"runtime/pprof"
|
"runtime/pprof"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
@ -66,23 +67,25 @@ func serverCheck(t *testing.T, serverAddr string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func waitForPeerGroupConnection(t *testing.T, peer peer.CwtchPeer, groupID string) {
|
func waitForPeerGroupConnection(t *testing.T, peer peer.CwtchPeer, groupID string) {
|
||||||
|
peerName, _ := peer.GetAttribute(attr.GetLocalScope("name"))
|
||||||
for {
|
for {
|
||||||
fmt.Printf("%v checking group connection...\n", peer.GetName())
|
fmt.Printf("%v checking group connection...\n", peerName)
|
||||||
state, ok := peer.GetGroupState(groupID)
|
state, ok := peer.GetGroupState(groupID)
|
||||||
if ok {
|
if ok {
|
||||||
fmt.Printf("Waiting for Peer %v to join group %v - state: %v\n", peer.GetName(), groupID, state)
|
fmt.Printf("Waiting for Peer %v to join group %v - state: %v\n", peerName, groupID, state)
|
||||||
if state == connections.FAILED {
|
if state == connections.FAILED {
|
||||||
t.Fatalf("%v could not connect to %v", peer.GetOnion(), groupID)
|
t.Fatalf("%v could not connect to %v", peer.GetOnion(), groupID)
|
||||||
}
|
}
|
||||||
if state != connections.SYNCED {
|
if state != connections.SYNCED {
|
||||||
fmt.Printf("peer %v %v waiting connect to group %v, currently: %v\n", peer.GetName(), peer.GetOnion(), groupID, connections.ConnectionStateName[state])
|
fmt.Printf("peer %v %v waiting connect to group %v, currently: %v\n", peerName, peer.GetOnion(), groupID, connections.ConnectionStateName[state])
|
||||||
time.Sleep(time.Second * 5)
|
time.Sleep(time.Second * 5)
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("peer %v %v CONNECTED to group %v\n", peer.GetName(), peer.GetOnion(), groupID)
|
fmt.Printf("peer %v %v CONNECTED to group %v\n", peerName, peer.GetOnion(), groupID)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
time.Sleep(time.Second * 2)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -100,7 +103,9 @@ func waitForPeerPeerConnection(t *testing.T, peera peer.CwtchPeer, peerb peer.Cw
|
||||||
time.Sleep(time.Second * 5)
|
time.Sleep(time.Second * 5)
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("%v CONNECTED and AUTHED to %v\n", peera.GetName(), peerb.GetName())
|
peerAName, _ := peera.GetAttribute(attr.GetLocalScope("name"))
|
||||||
|
peerBName, _ := peerb.GetAttribute(attr.GetLocalScope("name"))
|
||||||
|
fmt.Printf("%v CONNECTED and AUTHED to %v\n", peerAName, peerBName)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -300,12 +305,16 @@ func TestCwtchPeerIntegration(t *testing.T) {
|
||||||
time.Sleep(time.Second * 5)
|
time.Sleep(time.Second * 5)
|
||||||
|
|
||||||
fmt.Println("Bob examining groups and accepting invites...")
|
fmt.Println("Bob examining groups and accepting invites...")
|
||||||
for _, groupID := range bob.GetGroups() {
|
for _, message := range bob.GetContact(alice.GetOnion()).Timeline.GetMessages() {
|
||||||
group := bob.GetGroup(groupID)
|
fmt.Printf("Found message from Alice: %v", message.Message)
|
||||||
fmt.Printf("Bob group: %v (Accepted: %v)\n", group.GroupID, group.Accepted)
|
if strings.HasPrefix(message.Message, "torv3") {
|
||||||
if group.Accepted == false {
|
gid, err := bob.ImportGroup(message.Message)
|
||||||
fmt.Printf("Bob received and accepting group invite: %v\n", group.GroupID)
|
if err == nil {
|
||||||
bob.AcceptInvite(group.GroupID)
|
fmt.Printf("Bob found invite...now accepting %v...", gid)
|
||||||
|
bob.AcceptInvite(gid)
|
||||||
|
} else {
|
||||||
|
t.Fatalf("Bob could not accept invite...%v", gid)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,12 +356,16 @@ func TestCwtchPeerIntegration(t *testing.T) {
|
||||||
}
|
}
|
||||||
time.Sleep(time.Second * 60) // Account for some token acquisition in Alice and Bob flows.
|
time.Sleep(time.Second * 60) // Account for some token acquisition in Alice and Bob flows.
|
||||||
fmt.Println("Carol examining groups and accepting invites...")
|
fmt.Println("Carol examining groups and accepting invites...")
|
||||||
for _, groupID := range carol.GetGroups() {
|
for _, message := range carol.GetContact(alice.GetOnion()).Timeline.GetMessages() {
|
||||||
group := carol.GetGroup(groupID)
|
fmt.Printf("Found message from Alice: %v", message.Message)
|
||||||
fmt.Printf("Carol group: %v (Accepted: %v)\n", group.GroupID, group.Accepted)
|
if strings.HasPrefix(message.Message, "torv3") {
|
||||||
if group.Accepted == false {
|
gid, err := carol.ImportGroup(message.Message)
|
||||||
fmt.Printf("Carol received and accepting group invite: %v\n", group.GroupID)
|
if err == nil {
|
||||||
carol.AcceptInvite(group.GroupID)
|
fmt.Printf("Carol found invite...now accepting %v...", gid)
|
||||||
|
carol.AcceptInvite(gid)
|
||||||
|
} else {
|
||||||
|
t.Fatalf("Carol could not accept invite...%v", gid)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
this function... seems.. not great, and is only used by app/servermon? do we just want to remove that?
See below for my comment on App/Name and Profile.