From d13a8c30768dde7552db7b65c598fc417070b7e2 Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Sat, 9 Jun 2018 00:49:18 -0700 Subject: [PATCH] Adding import and exporting of groups to support alternative construction --- app/cli/main.go | 12 ++++++++++++ peer/cwtch_peer.go | 41 +++++++++++++++++++++++++++++++++++++++++ peer/cwtch_peer_test.go | 8 ++++++++ 3 files changed, 61 insertions(+) diff --git a/app/cli/main.go b/app/cli/main.go index 64c42dd..08a8ff4 100644 --- a/app/cli/main.go +++ b/app/cli/main.go @@ -325,6 +325,18 @@ func main() { } else { fmt.Printf("Error reading timeline from group, usage: %s\n", usages["timeline"]) } + case "export-group": + if len(commands) == 2 { + group := app.Peer.Profile.GetGroupByGroupID(commands[1]) + if group == nil { + fmt.Printf("Error: group does not exist\n") + } else { + invite, _ := app.Peer.ExportGroup(commands[1]) + fmt.Printf("Invite: %v\n", invite) + } + } else { + fmt.Printf("Error reading timeline from group, usage: %s\n", usages["timeline"]) + } case "save": app.Peer.Save(profilefile) case "help": diff --git a/peer/cwtch_peer.go b/peer/cwtch_peer.go index 60b616b..62c30a7 100644 --- a/peer/cwtch_peer.go +++ b/peer/cwtch_peer.go @@ -6,13 +6,17 @@ import ( "cwtch.im/cwtch/peer/connections" "cwtch.im/cwtch/peer/peer" "cwtch.im/cwtch/protocol" + "encoding/base64" "encoding/json" "errors" + "github.com/golang/protobuf/proto" "github.com/s-rah/go-ricochet/application" "github.com/s-rah/go-ricochet/channels" "github.com/s-rah/go-ricochet/connection" + "golang.org/x/crypto/ed25519" "io/ioutil" "log" + "strings" "sync" ) @@ -75,6 +79,43 @@ func LoadCwtchPeer(profilefile string) (*CwtchPeer, error) { return cp, err } +// ImportGroup intializes a group from an imported source rather than a peer invite +func (cp *CwtchPeer) ImportGroup(exportedInvite string) (groupID string, err error) { + if strings.HasPrefix(exportedInvite, "torv2") { + data, err := base64.StdEncoding.DecodeString(exportedInvite[21+44:]) + if err == nil { + cpp := &protocol.CwtchPeerPacket{} + err := proto.Unmarshal(data, cpp) + if err == nil { + pk, err := base64.StdEncoding.DecodeString(exportedInvite[21 : 21+44]) + if err == nil { + edpk := ed25519.PublicKey(pk) + onion := exportedInvite[5:21] + cp.Profile.AddContact(onion, &model.PublicProfile{"", edpk, true, false, onion}) + cp.Profile.ProcessInvite(cpp.GetGroupChatInvite(), onion) + return cpp.GroupChatInvite.GetGroupName(), nil + } + } + } + } else { + err = errors.New("unsupported exported group type") + } + return +} + +// ExportGroup serializes a group invite so it can be given offline +func (cp *CwtchPeer) ExportGroup(groupID string) (string, error) { + group := cp.Profile.GetGroupByGroupID(groupID) + if group != nil { + invite, err := group.Invite() + if err == nil { + exportedInvite := "torv2" + cp.Profile.Onion + base64.StdEncoding.EncodeToString(cp.Profile.Ed25519PublicKey) + base64.StdEncoding.EncodeToString(invite) + return exportedInvite, err + } + } + return "", errors.New("group id could not be found") +} + // PeerWithOnion is the entry point for CwtchPeer relationships func (cp *CwtchPeer) PeerWithOnion(onion string) { cp.connectionsManager.ManagePeerConnection(onion, cp.Profile) diff --git a/peer/cwtch_peer_test.go b/peer/cwtch_peer_test.go index 769b58e..4a57598 100644 --- a/peer/cwtch_peer_test.go +++ b/peer/cwtch_peer_test.go @@ -14,4 +14,12 @@ func TestCwtchPeerGenerate(t *testing.T) { t.Errorf("something went wrong saving and loading profiles %v %v", err, aliceLoaded) } + groupID, _, _ := aliceLoaded.Profile.StartGroup("test.server") + exportedGroup, _ := aliceLoaded.ExportGroup(groupID) + t.Logf("Exported Group: %v from %v", exportedGroup, aliceLoaded.Profile.Onion) + + importedGroupID, err := alice.ImportGroup(exportedGroup) + group := alice.Profile.GetGroupByGroupID(importedGroupID) + t.Logf("Imported Group: %v, err := %v %v", group, err, importedGroupID) + }