Rework group invite workflow: delete cwtchPacket references as no longer needed. Remove more events from being default handled by Peer (but allow them for some usecases still (testing, simple apps).
the build was successful Информация

Этот коммит содержится в:
Dan Ballard 2019-09-19 16:14:35 -07:00
родитель 304a55aa5e
Коммит 15582c7e79
12 изменённых файлов: 78 добавлений и 115 удалений

Просмотреть файл

@ -558,11 +558,11 @@ func main() {
}
case "/import-group":
if len(commands) == 2 {
groupID, err := peer.ImportGroup(commands[1])
err := peer.ImportGroup(commands[1])
if err != nil {
fmt.Printf("Error importing group: %v\n", err)
} else {
fmt.Printf("Imported group: %s\n", groupID)
fmt.Printf("Imported group!\n")
}
} else {
fmt.Printf("%v", commands)

Просмотреть файл

@ -37,7 +37,7 @@ type pipeBridge struct {
closedChan chan bool
state connections.ConnectionState
lock sync.Mutex
threeShake func () bool
threeShake func() bool
// For logging / debugging purposes
name string
@ -138,8 +138,8 @@ func (pb *pipeBridge) synLoop(stop chan bool) {
return
}
delay = time.Second
case <- stop:
return
case <-stop:
return
}
}
}

Просмотреть файл

@ -117,6 +117,7 @@ const (
// Data [eg "open privacy board"]
SetGroupAttribute = Type("SetGroupAttribute")
// PeerStateChange servers as a new incoming connection message as well, and can/is consumed by frontends to alert of new p2p connections
// RemotePeer
// ConnectionState
PeerStateChange = Type("PeerStateChange")

Просмотреть файл

@ -97,10 +97,7 @@ func (g *Group) Invite(initialMessage []byte) ([]byte, error) {
InitialMessage: initialMessage[:],
}
cp := &protocol.CwtchPeerPacket{
GroupChatInvite: gci,
}
invite, err := proto.Marshal(cp)
invite, err := proto.Marshal(gci)
return invite, err
}

Просмотреть файл

@ -1,8 +1,6 @@
package model
import (
"cwtch.im/cwtch/protocol"
"github.com/golang/protobuf/proto"
"strconv"
"testing"
"time"
@ -17,9 +15,8 @@ func TestMessagePadding(t *testing.T) {
alice.AddContact(sarah.Onion, &sarah.PublicProfile)
gid, invite, _ := alice.StartGroup("2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd")
gci := &protocol.CwtchPeerPacket{}
proto.Unmarshal(invite, gci)
sarah.ProcessInvite(gci.GetGroupChatInvite(), alice.Onion)
sarah.ProcessInvite(string(invite), alice.Onion)
group := alice.GetGroupByGroupID(gid)
@ -51,9 +48,8 @@ func TestTranscriptConsistency(t *testing.T) {
alice.AddContact(sarah.Onion, &sarah.PublicProfile)
gid, invite, _ := alice.StartGroup("2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd")
gci := &protocol.CwtchPeerPacket{}
proto.Unmarshal(invite, gci)
sarah.ProcessInvite(gci.GetGroupChatInvite(), alice.Onion)
sarah.ProcessInvite(string(invite), alice.Onion)
group := alice.GetGroupByGroupID(gid)

Просмотреть файл

@ -87,20 +87,6 @@ func GenerateNewProfile(name string) *Profile {
return p
}
// GetCwtchIdentityPacket returns the wire message for conveying this profiles identity.
func (p *Profile) GetCwtchIdentityPacket() (message []byte) {
ci := &protocol.CwtchIdentity{
Name: p.Name,
Ed25519PublicKey: p.Ed25519PublicKey,
}
cpp := &protocol.CwtchPeerPacket{
CwtchIdentify: ci,
}
message, err := proto.Marshal(cpp)
utils.CheckError(err)
return
}
// AddContact allows direct manipulation of cwtch contacts
func (p *Profile) AddContact(onion string, profile *PublicProfile) {
p.lock.Lock()
@ -317,19 +303,25 @@ func (p *Profile) GetGroupByGroupID(groupID string) (g *Group) {
return
}
// ProcessInvite adds a new group invite to the profile.
func (p *Profile) ProcessInvite(gci *protocol.GroupChatInvite, peerHostname string) {
group := new(Group)
group.GroupID = gci.GetGroupName()
group.LocalID = generateRandomID()
group.SignedGroupID = gci.GetSignedGroupId()
copy(group.GroupKey[:], gci.GetGroupSharedKey()[:])
group.GroupServer = gci.GetServerHost()
group.InitialMessage = gci.GetInitialMessage()[:]
group.Accepted = false
group.Owner = peerHostname
group.Attributes = make(map[string]string)
p.AddGroup(group)
// ProcessInvite adds a new group invite to the profile. returns the new group ID
func (p *Profile) ProcessInvite(invite string, peerHostname string) (string, error) {
var gci protocol.GroupChatInvite
err := proto.Unmarshal([]byte(invite), &gci)
if err == nil {
group := new(Group)
group.GroupID = gci.GetGroupName()
group.LocalID = generateRandomID()
group.SignedGroupID = gci.GetSignedGroupId()
copy(group.GroupKey[:], gci.GetGroupSharedKey()[:])
group.GroupServer = gci.GetServerHost()
group.InitialMessage = gci.GetInitialMessage()[:]
group.Accepted = false
group.Owner = peerHostname
group.Attributes = make(map[string]string)
p.AddGroup(group)
return group.GroupID, nil
}
return "", err
}
// AddGroup is a convenience method for adding a group to a profile.

Просмотреть файл

@ -1,23 +1,14 @@
package model
import (
"cwtch.im/cwtch/protocol"
"github.com/golang/protobuf/proto"
"testing"
)
func TestProfileIdentity(t *testing.T) {
sarah := GenerateNewProfile("Sarah")
alice := GenerateNewProfile("Alice")
message := sarah.GetCwtchIdentityPacket()
ci := &protocol.CwtchPeerPacket{}
err := proto.Unmarshal(message, ci)
if err != nil {
t.Errorf("alice should have added sarah as a contact %v", err)
}
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)
@ -78,9 +69,7 @@ func TestRejectGroupInvite(t *testing.T) {
alice.AddContact(sarah.Onion, &sarah.PublicProfile)
gid, invite, _ := alice.StartGroup("2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd")
gci := &protocol.CwtchPeerPacket{}
proto.Unmarshal(invite, gci)
sarah.ProcessInvite(gci.GetGroupChatInvite(), alice.Onion)
sarah.ProcessInvite(string(invite), alice.Onion)
group := alice.GetGroupByGroupID(gid)
if len(sarah.Groups) == 1 {
if sarah.GetGroupByGroupID(group.GroupID).Accepted {
@ -102,9 +91,7 @@ func TestProfileGroup(t *testing.T) {
alice.AddContact(sarah.Onion, &sarah.PublicProfile)
gid, invite, _ := alice.StartGroupWithMessage("2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd", []byte("Hello World"))
gci := &protocol.CwtchPeerPacket{}
proto.Unmarshal(invite, gci)
sarah.ProcessInvite(gci.GetGroupChatInvite(), alice.Onion)
sarah.ProcessInvite(string(invite), alice.Onion)
if len(sarah.GetGroups()) != 1 {
t.Errorf("sarah should only be in 1 group instead: %v", sarah.GetGroups())
}
@ -115,9 +102,7 @@ func TestProfileGroup(t *testing.T) {
alice.AttemptDecryption(c, s1)
gid2, invite2, _ := alice.StartGroup("2c3kmoobnyghj2zw6pwv7d57yzld753auo3ugauezzpvfak3ahc4bdyd")
gci2 := &protocol.CwtchPeerPacket{}
proto.Unmarshal(invite2, gci2)
sarah.ProcessInvite(gci2.GetGroupChatInvite(), alice.Onion)
sarah.ProcessInvite(string(invite2), alice.Onion)
group2 := alice.GetGroupByGroupID(gid2)
c2, s2, _ := sarah.EncryptMessageToGroup("Hello World", group2.GroupID)
alice.AttemptDecryption(c2, s2)
@ -135,7 +120,7 @@ func TestProfileGroup(t *testing.T) {
bob := GenerateNewProfile("bob")
bob.AddContact(alice.Onion, &alice.PublicProfile)
bob.ProcessInvite(gci2.GetGroupChatInvite(), alice.Onion)
bob.ProcessInvite(string(invite2), alice.Onion)
c3, s3, err := bob.EncryptMessageToGroup("Bobs Message", group2.GroupID)
if err == nil {
ok, _, message, _ := alice.AttemptDecryption(c3, s3)

Просмотреть файл

@ -3,19 +3,19 @@ package peer
import (
"cwtch.im/cwtch/event"
"cwtch.im/cwtch/model"
"cwtch.im/cwtch/protocol"
"cwtch.im/cwtch/protocol/connections"
"encoding/base32"
"encoding/base64"
"encoding/json"
"errors"
"git.openprivacy.ca/openprivacy/libricochet-go/log"
"github.com/golang/protobuf/proto"
"strings"
"sync"
"time"
)
var autoHandleableEvents = map[event.Type]bool{event.EncryptedGroupMessage: true, event.PeerStateChange: true, event.ServerStateChange: true, event.NewGroupInvite: true}
// cwtchPeer manages incoming and outgoing connections and all processing for a Cwtch cwtchPeer
type cwtchPeer struct {
Profile *model.Profile
@ -30,6 +30,7 @@ type cwtchPeer struct {
// directly implement a cwtchPeer.
type CwtchPeer interface {
Init(event.Manager)
AutoHandleEvents(events []event.Type)
PeerWithOnion(string)
InviteOnionToGroup(string, string) error
SendMessageToPeer(string, string) string
@ -51,7 +52,7 @@ type CwtchPeer interface {
StartGroup(string) (string, []byte, error)
ImportGroup(string) (string, error)
ImportGroup(string) error
ExportGroup(string) (string, error)
GetGroup(string) *model.Group
@ -79,6 +80,7 @@ func NewCwtchPeer(name string) CwtchPeer {
func FromProfile(profile *model.Profile) CwtchPeer {
cp := new(cwtchPeer)
cp.Profile = profile
cp.shutdown = false
return cp
}
@ -88,35 +90,34 @@ func (cp *cwtchPeer) Init(eventBus event.Manager) {
go cp.eventHandler()
cp.eventBus = eventBus
cp.eventBus.Subscribe(event.EncryptedGroupMessage, cp.queue)
cp.eventBus.Subscribe(event.NewGroupInvite, cp.queue)
cp.eventBus.Subscribe(event.ServerStateChange, cp.queue)
cp.eventBus.Subscribe(event.PeerStateChange, cp.queue)
cp.AutoHandleEvents([]event.Type{event.EncryptedGroupMessage})
}
// AutoHandleEvents sets an event (if able) to be handled by this peer
func (cp *cwtchPeer) AutoHandleEvents(events []event.Type) {
for _, ev := range events {
if _, exists := autoHandleableEvents[ev]; exists {
cp.eventBus.Subscribe(ev, cp.queue)
} else {
log.Errorf("Peer asked to autohandle event it cannot: %v\n", ev)
}
}
}
// ImportGroup intializes a group from an imported source rather than a peer invite
func (cp *cwtchPeer) ImportGroup(exportedInvite string) (groupID string, err error) {
func (cp *cwtchPeer) ImportGroup(exportedInvite string) (err error) {
if strings.HasPrefix(exportedInvite, "torv3") {
data, err := base64.StdEncoding.DecodeString(exportedInvite[5+44:])
data, err := base64.StdEncoding.DecodeString(exportedInvite[5:])
if err == nil {
cpp := &protocol.CwtchPeerPacket{}
err = proto.Unmarshal(data, cpp)
if err == nil {
jsobj, err := proto.Marshal(cpp.GetGroupChatInvite())
if err == nil {
cp.eventBus.Publish(event.NewEvent(event.NewGroupInvite, map[event.Field]string{
event.GroupInvite: string(jsobj),
}))
} else {
log.Errorf("error serializing group: %v", err)
}
return cpp.GroupChatInvite.GetGroupName(), nil
}
cp.eventBus.Publish(event.NewEvent(event.NewGroupInvite, map[event.Field]string{
event.GroupInvite: string(data),
}))
} else {
log.Errorf("error decoding group invite: %v", err)
}
} else {
err = errors.New("unsupported exported group type")
return nil
}
return
return errors.New("unsupported exported group type")
}
// ExportGroup serializes a group invite so it can be given offline
@ -125,7 +126,7 @@ func (cp *cwtchPeer) ExportGroup(groupID string) (string, error) {
if group != nil {
invite, err := group.Invite(group.GetInitialMessage())
if err == nil {
exportedInvite := "torv3" + base64.StdEncoding.EncodeToString(cp.Profile.Ed25519PublicKey) + base64.StdEncoding.EncodeToString(invite)
exportedInvite := "torv3" + base64.StdEncoding.EncodeToString(invite)
return exportedInvite, err
}
}
@ -342,18 +343,18 @@ func (cp *cwtchPeer) eventHandler() {
for {
ev := cp.queue.Next()
switch ev.EventType {
/***** Default auto handled events *****/
case event.EncryptedGroupMessage:
ok, groupID, message, seen := cp.Profile.AttemptDecryption([]byte(ev.Data[event.Ciphertext]), []byte(ev.Data[event.Signature]))
if ok && !seen {
cp.eventBus.Publish(event.NewEvent(event.NewMessageFromGroup, map[event.Field]string{event.TimestampReceived: message.Received.Format(time.RFC3339Nano), event.TimestampSent: message.Timestamp.Format(time.RFC3339Nano), event.Data: message.Message, event.GroupID: groupID, event.Signature: string(message.Signature), event.PreviousSignature: string(message.PreviousMessageSig), event.RemotePeer: message.PeerID}))
}
/***** Non default but requestable handlable events *****/
case event.NewGroupInvite:
var groupInvite protocol.GroupChatInvite
err := proto.Unmarshal([]byte(ev.Data[event.GroupInvite]), &groupInvite)
if err != nil {
log.Errorf("NewGroupInvite could not json decode invite: %v\n", err)
}
cp.Profile.ProcessInvite(&groupInvite, ev.Data[event.RemotePeer])
cp.Profile.ProcessInvite(ev.Data[event.GroupInvite], ev.Data[event.RemotePeer])
case event.PeerStateChange:
if _, exists := cp.Profile.Contacts[ev.Data[event.RemotePeer]]; exists {
cp.Profile.Contacts[ev.Data[event.RemotePeer]].State = ev.Data[event.ConnectionState]
@ -364,6 +365,7 @@ func (cp *cwtchPeer) eventHandler() {
group.State = ev.Data[event.ConnectionState]
}
}
default:
if ev.EventType != "" {
log.Errorf("peer event handler received an event it was not subscribed for: %v", ev.EventType)

Просмотреть файл

@ -11,7 +11,6 @@ import (
"git.openprivacy.ca/openprivacy/libricochet-go/connectivity"
"git.openprivacy.ca/openprivacy/libricochet-go/log"
"git.openprivacy.ca/openprivacy/libricochet-go/utils"
"github.com/golang/protobuf/proto"
"golang.org/x/crypto/ed25519"
"sync"
"time"
@ -332,12 +331,7 @@ func (e *engine) sendMessageToGroup(server string, ct []byte, sig []byte) {
func (e *engine) handlePeerMessage(hostname string, context string, message []byte) {
log.Debugf("New message from peer: %v %v", hostname, context)
if context == event.ContextInvite {
cpp := &protocol.CwtchPeerPacket{}
err := proto.Unmarshal(message, cpp)
if err == nil && cpp.GetGroupChatInvite() != nil {
marshal, _ := proto.Marshal(cpp.GetGroupChatInvite())
e.eventManager.Publish(event.NewEvent(event.NewGroupInvite, map[event.Field]string{event.TimestampReceived: time.Now().Format(time.RFC3339Nano), event.RemotePeer: hostname, event.GroupInvite: string(marshal)}))
}
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 {
e.eventManager.Publish(event.NewEvent(event.NewMessageFromPeer, map[event.Field]string{event.TimestampReceived: time.Now().Format(time.RFC3339Nano), event.RemotePeer: hostname, event.Data: string(message)}))
}

Просмотреть файл

@ -3,10 +3,8 @@ package storage
import (
"cwtch.im/cwtch/event"
"cwtch.im/cwtch/model"
"cwtch.im/cwtch/protocol"
"encoding/json"
"git.openprivacy.ca/openprivacy/libricochet-go/log"
"github.com/golang/protobuf/proto"
"os"
"time"
)
@ -212,15 +210,14 @@ func (ps *profileStore) eventHandler() {
log.Errorf("error accepting group invite")
}
case event.NewGroupInvite:
var gci protocol.GroupChatInvite
err := proto.Unmarshal([]byte(ev.Data[event.GroupInvite]), &gci)
gid, err := ps.profile.ProcessInvite(ev.Data[event.GroupInvite], ev.Data[event.RemotePeer])
log.Errorf("gid: %v err:%v\n", gid, err)
if err == nil {
ps.profile.ProcessInvite(&gci, ev.Data[event.RemotePeer])
ps.save()
group := ps.profile.Groups[gci.GetGroupName()]
group := ps.profile.Groups[gid]
ps.streamStores[group.GroupID] = NewStreamStore(ps.directory, group.LocalID, ps.password)
} else {
log.Errorf("error storing new group invite: %v %v", ev, err)
log.Errorf("error storing new group invite: %v (%v)", err, ev)
}
case event.NewMessageFromGroup:
groupid := ev.Data[event.GroupID]

Просмотреть файл

@ -2,8 +2,6 @@ package storage
import (
"cwtch.im/cwtch/event"
"cwtch.im/cwtch/protocol"
"github.com/golang/protobuf/proto"
"os"
"testing"
"time"
@ -32,9 +30,6 @@ func TestProfileStoreWriteRead(t *testing.T) {
t.Errorf("Creating group invite: %v\n", err)
}
packet := protocol.CwtchPeerPacket{}
proto.Unmarshal(invite, &packet)
invite, _ = proto.Marshal(packet.GetGroupChatInvite())
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)}))
time.Sleep(1 * time.Second)

Просмотреть файл

@ -3,6 +3,7 @@ package testing
import (
app2 "cwtch.im/cwtch/app"
"cwtch.im/cwtch/app/utils"
"cwtch.im/cwtch/event"
"cwtch.im/cwtch/event/bridge"
"cwtch.im/cwtch/model"
"cwtch.im/cwtch/peer"
@ -163,12 +164,15 @@ func TestCwtchPeerIntegration(t *testing.T) {
alice := utils.WaitGetPeer(app, "alice")
fmt.Println("Alice created:", alice.GetProfile().Onion)
alice.AutoHandleEvents([]event.Type{event.PeerStateChange, event.ServerStateChange, event.NewGroupInvite})
bob := utils.WaitGetPeer(app, "bob")
fmt.Println("Bob created:", bob.GetProfile().Onion)
bob.AutoHandleEvents([]event.Type{event.PeerStateChange, event.ServerStateChange, event.NewGroupInvite})
carol := utils.WaitGetPeer(appClient, "carol")
fmt.Println("Carol created:", carol.GetProfile().Onion)
carol.AutoHandleEvents([]event.Type{event.PeerStateChange, event.ServerStateChange, event.NewGroupInvite})
app.LaunchPeers()
appClient.LaunchPeers()