Upgrade Dependencies + Clean up Groups #350
|
@ -69,7 +69,7 @@ func (ap *appletPeers) ListPeers() map[string]string {
|
|||
ap.peerLock.Lock()
|
||||
defer ap.peerLock.Unlock()
|
||||
for k, p := range ap.peers {
|
||||
keys[k] = p.GetName()
|
||||
keys[k] = p.GetOnion()
|
||||
}
|
||||
return keys
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package utils
|
|||
|
||||
import (
|
||||
app2 "cwtch.im/cwtch/app"
|
||||
"cwtch.im/cwtch/model/attr"
|
||||
"cwtch.im/cwtch/peer"
|
||||
"time"
|
||||
)
|
||||
|
@ -12,9 +13,11 @@ import (
|
|||
// may fill that usecase better
|
||||
func WaitGetPeer(app app2.Application, name string) peer.CwtchPeer {
|
||||
dan marked this conversation as resolved
|
||||
for true {
|
||||
for id, n := range app.ListPeers() {
|
||||
if n == name {
|
||||
return app.GetPeer(id)
|
||||
for id := range app.ListPeers() {
|
||||
peer := app.GetPeer(id)
|
||||
localName, _ := peer.GetAttribute(attr.GetLocalScope("name"))
|
||||
if localName == name {
|
||||
return peer
|
||||
}
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
|
|
@ -13,8 +13,6 @@ import (
|
|||
"sync"
|
||||
)
|
||||
|
||||
|
||||
|
||||
// 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.
|
||||
type Event struct {
|
||||
|
@ -86,7 +84,6 @@ func (em *manager) initialize() {
|
|||
em.internal = make(chan bool)
|
||||
em.closed = false
|
||||
|
||||
|
||||
_, em.trace = os.LookupEnv("CWTCH_EVENT_SOURCE")
|
||||
|
||||
go em.eventBus()
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"crypto/rand"
|
||||
"cwtch.im/cwtch/model/attr"
|
||||
"cwtch.im/cwtch/protocol/groups"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
@ -27,9 +28,7 @@ type Group struct {
|
|||
GroupServer string
|
||||
Timeline Timeline `json:"-"`
|
||||
Accepted bool
|
||||
Owner string
|
||||
IsCompromised bool
|
||||
InitialMessage []byte
|
||||
Attributes map[string]string
|
||||
lock sync.Mutex
|
||||
LocalID string
|
||||
|
@ -63,7 +62,6 @@ func NewGroup(server string) (*Group, error) {
|
|||
return nil, err
|
||||
}
|
||||
copy(group.GroupKey[:], groupKey[:])
|
||||
group.Owner = "self"
|
||||
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
|
||||
// codes around invite, we assume that this is always set.
|
||||
|
@ -82,33 +80,24 @@ func (g *Group) Compromised() {
|
|||
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
|
||||
func (g *Group) Invite(initialMessage []byte) ([]byte, error) {
|
||||
func (g *Group) Invite() (string, error) {
|
||||
|
||||
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{
|
||||
GroupID: g.GroupID,
|
||||
GroupName: g.Attributes[attr.GetLocalScope("name")],
|
||||
SharedKey: g.GroupKey[:],
|
||||
ServerHost: g.GroupServer,
|
||||
SignedGroupID: g.SignedGroupID[:],
|
||||
InitialMessage: initialMessage[:],
|
||||
}
|
||||
|
||||
invite, err := json.Marshal(gci)
|
||||
return invite, err
|
||||
serializedInvite := fmt.Sprintf("%v\n", "torv3"+base64.StdEncoding.EncodeToString(invite))
|
||||
return serializedInvite, err
|
||||
}
|
||||
|
||||
// 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")
|
||||
|
||||
sarah.ProcessInvite(string(invite), alice.Onion)
|
||||
sarah.ProcessInvite(invite)
|
||||
|
||||
group := alice.GetGroup(gid)
|
||||
|
||||
|
@ -49,7 +49,7 @@ func TestTranscriptConsistency(t *testing.T) {
|
|||
|
||||
gid, invite, _ := alice.StartGroup("2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd")
|
||||
|
||||
sarah.ProcessInvite(string(invite), alice.Onion)
|
||||
sarah.ProcessInvite(invite)
|
||||
|
||||
group := alice.GetGroup(gid)
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import (
|
|||
"crypto/rand"
|
||||
"cwtch.im/cwtch/protocol/groups"
|
||||
"encoding/base32"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"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
|
||||
// invite which can be sent on the wire.
|
||||
func (p *Profile) StartGroup(server string) (groupID string, invite []byte, 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) {
|
||||
func (p *Profile) StartGroup(server string) (groupID string, invite string, err error) {
|
||||
group, err := NewGroup(server)
|
||||
if err != nil {
|
||||
return "", nil, err
|
||||
return "", "", err
|
||||
}
|
||||
groupID = group.GroupID
|
||||
group.Owner = p.Onion
|
||||
signedGroupID := p.SignMessage(groupID + server)
|
||||
group.SignGroup(signedGroupID)
|
||||
invite, err = group.Invite(initialMessage)
|
||||
invite, err = group.Invite()
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
p.Groups[group.GroupID] = group
|
||||
|
@ -364,9 +358,12 @@ func (p *Profile) GetGroup(groupID string) (g *Group) {
|
|||
}
|
||||
|
||||
// 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) {
|
||||
if strings.HasPrefix(invite, "torv3") {
|
||||
data, err := base64.StdEncoding.DecodeString(invite[5:])
|
||||
if err == nil {
|
||||
var gci groups.GroupInvite
|
||||
err := json.Unmarshal([]byte(invite), &gci)
|
||||
err := json.Unmarshal(data, &gci)
|
||||
if err == nil {
|
||||
group := new(Group)
|
||||
group.Version = CurrentGroupVersion
|
||||
|
@ -375,22 +372,22 @@ func (p *Profile) ProcessInvite(invite string, peerHostname string) (string, str
|
|||
group.SignedGroupID = gci.SignedGroupID
|
||||
copy(group.GroupKey[:], gci.SharedKey[:])
|
||||
group.GroupServer = gci.ServerHost
|
||||
group.InitialMessage = []byte(gci.InitialMessage)
|
||||
group.Accepted = false
|
||||
group.Owner = peerHostname
|
||||
group.Attributes = make(map[string]string)
|
||||
p.AddGroup(group)
|
||||
return group.GroupID, gci.GroupName, nil
|
||||
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.
|
||||
func (p *Profile) AddGroup(group *Group) {
|
||||
_, exists := p.Groups[group.GroupID]
|
||||
if !exists {
|
||||
p.lock.Lock()
|
||||
defer p.lock.Unlock()
|
||||
_, exists := p.Groups[group.GroupID]
|
||||
if !exists {
|
||||
p.Groups[group.GroupID] = group
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ func TestRejectGroupInvite(t *testing.T) {
|
|||
alice.AddContact(sarah.Onion, &sarah.PublicProfile)
|
||||
|
||||
gid, invite, _ := alice.StartGroup("2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd")
|
||||
sarah.ProcessInvite(string(invite), alice.Onion)
|
||||
sarah.ProcessInvite(invite)
|
||||
group := alice.GetGroup(gid)
|
||||
if len(sarah.Groups) == 1 {
|
||||
if sarah.GetGroup(group.GroupID).Accepted {
|
||||
|
@ -85,8 +85,8 @@ func TestProfileGroup(t *testing.T) {
|
|||
sarah.AddContact(alice.Onion, &alice.PublicProfile)
|
||||
alice.AddContact(sarah.Onion, &sarah.PublicProfile)
|
||||
|
||||
gid, invite, _ := alice.StartGroupWithMessage("2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd", []byte("Hello World"))
|
||||
sarah.ProcessInvite(string(invite), alice.Onion)
|
||||
gid, invite, _ := alice.StartGroup("2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd")
|
||||
sarah.ProcessInvite(invite)
|
||||
if len(sarah.GetGroups()) != 1 {
|
||||
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)
|
||||
|
||||
gid2, invite2, _ := alice.StartGroup("2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd")
|
||||
sarah.ProcessInvite(string(invite2), alice.Onion)
|
||||
sarah.ProcessInvite(invite2)
|
||||
group2 := alice.GetGroup(gid2)
|
||||
c2, s2, _ := sarah.EncryptMessageToGroup("Hello World", group2.GroupID)
|
||||
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)
|
||||
if err == nil {
|
||||
t.Errorf("Overly long message should have returned an error")
|
||||
|
@ -115,7 +109,7 @@ func TestProfileGroup(t *testing.T) {
|
|||
|
||||
bob := GenerateNewProfile("bob")
|
||||
bob.AddContact(alice.Onion, &alice.PublicProfile)
|
||||
bob.ProcessInvite(string(invite2), alice.Onion)
|
||||
bob.ProcessInvite(invite2)
|
||||
c3, s3, err := bob.EncryptMessageToGroup("Bobs Message", group2.GroupID)
|
||||
if err == nil {
|
||||
ok, _, message, _ := alice.AttemptDecryption(c3, s3)
|
||||
|
|
|
@ -109,8 +109,8 @@ type ReadGroups interface {
|
|||
|
||||
// ModifyGroups provides write-only access add/edit/remove new groups
|
||||
type ModifyGroups interface {
|
||||
ImportGroup(string) error
|
||||
StartGroup(string) (string, []byte, error)
|
||||
ImportGroup(string) (string, error)
|
||||
StartGroup(string) (string, string, error)
|
||||
AcceptInvite(string) error
|
||||
RejectInvite(string)
|
||||
DeleteGroup(string)
|
||||
|
@ -172,14 +172,6 @@ type CwtchPeer interface {
|
|||
|
||||
SendMessages
|
||||
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.
|
||||
|
@ -223,20 +215,16 @@ func (cp *cwtchPeer) AutoHandleEvents(events []event.Type) {
|
|||
}
|
||||
|
||||
// ImportGroup initializes a group from an imported source rather than a peer invite
|
||||
func (cp *cwtchPeer) ImportGroup(exportedInvite string) (err error) {
|
||||
if strings.HasPrefix(exportedInvite, "torv3") {
|
||||
data, err := base64.StdEncoding.DecodeString(exportedInvite[5:])
|
||||
func (cp *cwtchPeer) ImportGroup(exportedInvite string) (string, error) {
|
||||
cp.mutex.Lock()
|
||||
defer cp.mutex.Unlock()
|
||||
gid, err := cp.Profile.ProcessInvite(exportedInvite)
|
||||
|
||||
if err == nil {
|
||||
cp.eventBus.Publish(event.NewEvent(event.NewGroupInvite, map[event.Field]string{
|
||||
event.GroupInvite: string(data),
|
||||
event.Imported: "true",
|
||||
}))
|
||||
} else {
|
||||
log.Errorf("error decoding group invite: %v", err)
|
||||
cp.eventBus.Publish(event.NewEvent(event.NewGroup, map[event.Field]string{event.GroupID: gid, event.GroupInvite: exportedInvite}))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return errors.New("unsupported exported group type")
|
||||
|
||||
return gid, err
|
||||
}
|
||||
|
||||
// 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()
|
||||
group := cp.Profile.GetGroup(groupID)
|
||||
if group != nil {
|
||||
invite, err := group.Invite(group.GetInitialMessage())
|
||||
if err == nil {
|
||||
exportedInvite := "torv3" + base64.StdEncoding.EncodeToString(invite)
|
||||
return exportedInvite, err
|
||||
}
|
||||
return group.Invite()
|
||||
}
|
||||
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.
|
||||
func (cp *cwtchPeer) StartGroup(server string) (string, []byte, 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) {
|
||||
func (cp *cwtchPeer) StartGroup(server string) (string, string, error) {
|
||||
cp.mutex.Lock()
|
||||
groupID, invite, err = cp.Profile.StartGroupWithMessage(server, initialMessage)
|
||||
groupID, invite, err := cp.Profile.StartGroup(server)
|
||||
cp.mutex.Unlock()
|
||||
if err == nil {
|
||||
group := cp.GetGroup(groupID)
|
||||
|
@ -275,7 +254,7 @@ func (cp *cwtchPeer) StartGroupWithMessage(server string, initialMessage []byte)
|
|||
} else {
|
||||
log.Errorf("error creating group: %v", err)
|
||||
}
|
||||
return
|
||||
return groupID, invite, err
|
||||
}
|
||||
|
||||
// GetGroups returns an unordered list of all group IDs.
|
||||
|
@ -400,18 +379,6 @@ func (cp *cwtchPeer) GetContact(onion string) *model.PublicProfile {
|
|||
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 {
|
||||
cp.mutex.Lock()
|
||||
defer cp.mutex.Unlock()
|
||||
|
@ -465,14 +432,13 @@ func (cp *cwtchPeer) DeleteGroup(groupID string) {
|
|||
func (cp *cwtchPeer) InviteOnionToGroup(onion string, groupid string) error {
|
||||
cp.mutex.Lock()
|
||||
group := cp.Profile.GetGroup(groupid)
|
||||
defer cp.mutex.Unlock()
|
||||
if group == nil {
|
||||
return errors.New("invalid group id")
|
||||
}
|
||||
|
||||
invite, err := group.Invite(group.InitialMessage)
|
||||
invite, err := group.Invite()
|
||||
cp.mutex.Unlock()
|
||||
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
|
||||
}
|
||||
|
@ -537,13 +503,6 @@ func (cp *cwtchPeer) SetContactAuthorization(peer string, authorization model.Au
|
|||
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
|
||||
func (cp *cwtchPeer) AcceptInvite(groupID string) error {
|
||||
cp.mutex.Lock()
|
||||
|
@ -615,6 +574,11 @@ func (cp *cwtchPeer) GetAttribute(key string) (string, bool) {
|
|||
if val, exists := cp.Profile.GetAttribute(key); exists {
|
||||
return val, true
|
||||
}
|
||||
|
||||
if key == attr.GetLocalScope("name") {
|
||||
return cp.Profile.Name, true
|
||||
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 "", false
|
||||
}
|
||||
|
||||
|
@ -772,23 +736,6 @@ func (cp *cwtchPeer) eventHandler() {
|
|||
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:
|
||||
cp.mutex.Lock()
|
||||
if _, exists := cp.Profile.Contacts[ev.Data[event.RemotePeer]]; exists {
|
||||
|
|
|
@ -468,10 +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) {
|
||||
log.Debugf("New message from peer: %v %v", hostname, context)
|
||||
if context == event.ContextInvite {
|
||||
// TODO: Convert this to an inline peer message...
|
||||
// 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 {
|
||||
if context == event.ContextGetVal {
|
||||
var getVal peerGetVal
|
||||
err := json.Unmarshal(message, &getVal)
|
||||
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
|
||||
}
|
|
@ -17,7 +17,6 @@ type GroupInvite struct {
|
|||
Timestamp uint64
|
||||
SharedKey []byte
|
||||
ServerHost string
|
||||
InitialMessage []byte
|
||||
}
|
||||
|
||||
// DecryptedGroupMessage is the main encapsulation of group message data
|
||||
|
|
|
@ -21,6 +21,7 @@ const (
|
|||
func main() {
|
||||
log.AddEverythingFromPattern("server/app/main")
|
||||
log.AddEverythingFromPattern("server/server")
|
||||
log.SetLevel(log.LevelDebug)
|
||||
configDir := os.Getenv("CWTCH_CONFIG_DIR")
|
||||
|
||||
if len(os.Args) == 2 && os.Args[1] == "gen1" {
|
||||
|
@ -73,14 +74,17 @@ func main() {
|
|||
// TODO create a random group for testing
|
||||
group, _ := model.NewGroup(tor.GetTorV3Hostname(serverConfig.PublicKey))
|
||||
group.SignGroup([]byte{})
|
||||
invite, err := group.Invite([]byte{})
|
||||
invite, err := group.Invite()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Printf("%v\n", "torv3"+base64.StdEncoding.EncodeToString(invite))
|
||||
fmt.Printf("Invite: %v", invite)
|
||||
|
||||
bundle := server.KeyBundle().Serialize()
|
||||
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)
|
||||
for {
|
||||
time.Sleep(time.Second)
|
||||
|
|
|
@ -39,7 +39,7 @@ type Server struct {
|
|||
func (s *Server) Setup(serverConfig Config) {
|
||||
s.config = serverConfig
|
||||
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.tokenService = s.config.TokenServiceIdentity()
|
||||
s.tokenServicePrivKey = s.config.TokenServerPrivateKey
|
||||
|
|
|
@ -42,7 +42,7 @@ func TestProfileStoreUpgradeV0toV1(t *testing.T) {
|
|||
t.Errorf("Creating group invite: %v\n", err)
|
||||
}
|
||||
|
||||
ps1.AddGroup(invite, profile.Onion)
|
||||
ps1.AddGroup(invite)
|
||||
|
||||
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)
|
||||
func (ps *ProfileStoreV0) AddGroup(invite []byte, peer string) {
|
||||
gid, _, err := ps.profile.ProcessInvite(string(invite), peer)
|
||||
func (ps *ProfileStoreV0) AddGroup(invite string) {
|
||||
gid, err := ps.profile.ProcessInvite(invite)
|
||||
if err == nil {
|
||||
ps.save()
|
||||
group := ps.profile.Groups[gid]
|
||||
|
|
|
@ -40,7 +40,7 @@ func TestProfileStoreWriteRead(t *testing.T) {
|
|||
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)
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ func (ps *ProfileStoreV1) initProfileWriterStore() {
|
|||
ps.eventManager.Subscribe(event.SetGroupAttribute, ps.queue)
|
||||
ps.eventManager.Subscribe(event.AcceptGroupInvite, 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.SendMessageToPeer, ps.queue)
|
||||
ps.eventManager.Subscribe(event.PeerAcknowledgement, ps.queue)
|
||||
|
@ -377,8 +377,8 @@ func (ps *ProfileStoreV1) eventHandler() {
|
|||
case event.RejectGroupInvite:
|
||||
ps.profile.RejectInvite(ev.Data[event.GroupID])
|
||||
ps.save()
|
||||
case event.NewGroupInvite:
|
||||
gid, _, err := ps.profile.ProcessInvite(ev.Data[event.GroupInvite], ev.Data[event.RemotePeer])
|
||||
case event.NewGroup:
|
||||
gid, err := ps.profile.ProcessInvite(ev.Data[event.GroupInvite])
|
||||
if err == nil {
|
||||
ps.save()
|
||||
group := ps.profile.Groups[gid]
|
||||
|
|
|
@ -35,7 +35,7 @@ func TestProfileStoreWriteRead(t *testing.T) {
|
|||
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)
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
fmt.Println("Sending 200 messages...")
|
||||
|
|
|
@ -23,6 +23,7 @@ import (
|
|||
"path"
|
||||
"runtime"
|
||||
"runtime/pprof"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
@ -66,23 +67,25 @@ func serverCheck(t *testing.T, serverAddr string) bool {
|
|||
}
|
||||
|
||||
func waitForPeerGroupConnection(t *testing.T, peer peer.CwtchPeer, groupID string) {
|
||||
peerName, _ := peer.GetAttribute(attr.GetLocalScope("name"))
|
||||
for {
|
||||
fmt.Printf("%v checking group connection...\n", peer.GetName())
|
||||
fmt.Printf("%v checking group connection...\n", peerName)
|
||||
state, ok := peer.GetGroupState(groupID)
|
||||
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 {
|
||||
t.Fatalf("%v could not connect to %v", peer.GetOnion(), groupID)
|
||||
}
|
||||
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)
|
||||
continue
|
||||
} 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
|
||||
}
|
||||
}
|
||||
time.Sleep(time.Second * 2)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
@ -100,7 +103,9 @@ func waitForPeerPeerConnection(t *testing.T, peera peer.CwtchPeer, peerb peer.Cw
|
|||
time.Sleep(time.Second * 5)
|
||||
continue
|
||||
} 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
|
||||
}
|
||||
}
|
||||
|
@ -300,12 +305,16 @@ func TestCwtchPeerIntegration(t *testing.T) {
|
|||
time.Sleep(time.Second * 5)
|
||||
|
||||
fmt.Println("Bob examining groups and accepting invites...")
|
||||
for _, groupID := range bob.GetGroups() {
|
||||
group := bob.GetGroup(groupID)
|
||||
fmt.Printf("Bob group: %v (Accepted: %v)\n", group.GroupID, group.Accepted)
|
||||
if group.Accepted == false {
|
||||
fmt.Printf("Bob received and accepting group invite: %v\n", group.GroupID)
|
||||
bob.AcceptInvite(group.GroupID)
|
||||
for _, message := range bob.GetContact(alice.GetOnion()).Timeline.GetMessages() {
|
||||
fmt.Printf("Found message from Alice: %v", message.Message)
|
||||
if strings.HasPrefix(message.Message, "torv3") {
|
||||
gid, err := bob.ImportGroup(message.Message)
|
||||
if err == nil {
|
||||
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.
|
||||
fmt.Println("Carol examining groups and accepting invites...")
|
||||
for _, groupID := range carol.GetGroups() {
|
||||
group := carol.GetGroup(groupID)
|
||||
fmt.Printf("Carol group: %v (Accepted: %v)\n", group.GroupID, group.Accepted)
|
||||
if group.Accepted == false {
|
||||
fmt.Printf("Carol received and accepting group invite: %v\n", group.GroupID)
|
||||
carol.AcceptInvite(group.GroupID)
|
||||
for _, message := range carol.GetContact(alice.GetOnion()).Timeline.GetMessages() {
|
||||
fmt.Printf("Found message from Alice: %v", message.Message)
|
||||
if strings.HasPrefix(message.Message, "torv3") {
|
||||
gid, err := carol.ImportGroup(message.Message)
|
||||
if err == nil {
|
||||
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.