From fffe18344ec37acb8c41212174a012b40e892d0a Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Fri, 27 Apr 2018 12:20:33 -0700 Subject: [PATCH 1/4] expand integ test: - run own server; delete pk from repo - tests check and use test server if available (faster) - alice & bob users - chat - pretty print results - verify messages and content TODO: disconnect and reconnect to confirm offline delivery - server: autogenerate private key --- server/server.go | 12 ++ .../cwtch_peer_server_intergration_test.go | 171 ++++++++++++++++-- testing/private_key | 15 -- 3 files changed, 170 insertions(+), 28 deletions(-) delete mode 100644 testing/private_key diff --git a/server/server.go b/server/server.go index 70ac609..b0063ba 100644 --- a/server/server.go +++ b/server/server.go @@ -9,6 +9,8 @@ import ( "github.com/s-rah/go-ricochet/channels" "github.com/s-rah/go-ricochet/utils" "log" + "os" + "io/ioutil" ) // Server encapsulates a complete, compliant Cwtch server. @@ -21,6 +23,16 @@ type Server struct { func (s *Server) Run(privateKeyFile string) { cwtchserver := new(application.RicochetApplication) + if _, err := os.Stat(privateKeyFile); os.IsNotExist(err) { + log.Printf("no private key found!") + log.Printf("generating new private key...") + pk, pk_err := utils.GeneratePrivateKey() + if pk_err != nil { + log.Fatalf("error generating new private key: %v", err) + } + ioutil.WriteFile(privateKeyFile, []byte(utils.PrivateKeyToString(pk)), 0400) + } + pk, err := utils.LoadPrivateKeyFromFile(privateKeyFile) if err != nil { diff --git a/testing/cwtch_peer_server_intergration_test.go b/testing/cwtch_peer_server_intergration_test.go index 697150d..9faae1d 100644 --- a/testing/cwtch_peer_server_intergration_test.go +++ b/testing/cwtch_peer_server_intergration_test.go @@ -1,22 +1,167 @@ package testing import ( + cwtchserver "git.mascherari.press/cwtch/server" + "github.com/s-rah/go-ricochet/utils" "git.mascherari.press/cwtch/peer" "testing" "time" + "log" + "git.mascherari.press/cwtch/protocol" + "github.com/golang/protobuf/proto" + "io/ioutil" + "fmt" + "git.mascherari.press/cwtch/model" + "os" + "github.com/s-rah/go-ricochet" ) -func TestCwtchPeerIntegration(t *testing.T) { - alice := peer.NewCwtchPeer("Alice") - id, _ := alice.Profile.StartGroup("ylhbhtypevo4ympq") - alice.Profile.AddContact(alice.Profile.Onion, alice.Profile.PublicProfile) - alice.JoinServer("ylhbhtypevo4ympq") - // time.Sleep(time.Second *5) - alice.SendMessageToGroup(id, "Hello") - alice.SendMessageToGroup(id, "My") - alice.SendMessageToGroup(id, "Name Is") - alice.SendMessageToGroup(id, "ALICE!!!") - time.Sleep(time.Second * 5) - group := alice.Profile.Groups[id] - t.Logf("%v", group.Timeline) +const ( + keyfile = "./private_key" +) + +var ( + aliceLines = []string {"Hello", "My name is Alice", "bye"} + bobLines = []string {"Hi", "My name is Bob.", "toodles", "hello?"} + +) + +func checkAndGenPrivateKey(privateKeyFile string) (generated bool){ + if _, err := os.Stat(privateKeyFile); os.IsNotExist(err) { + fmt.Println("generating new private key...") + pk, pk_err := utils.GeneratePrivateKey() + if pk_err != nil { + log.Fatalf("error generating new private key: %v\n", err) + } + err := ioutil.WriteFile(privateKeyFile, []byte(utils.PrivateKeyToString(pk)), 0400) + if err != nil { + log.Fatalf("error writing new private key to file %s: %v\n", privateKeyFile, err) + } + return true + } + return false +} + +func printAndVerifyTimeline(t *testing.T, timeline model.Timeline) error { + for _, message := range timeline.Messages { + fmt.Printf("%v %v> %s [%t]\n", message.Timestamp, message.PeerID, message.Message, message.Verified) + if !message.Verified { + t.Errorf("Message '%s' from '%s' not verified!", message.Message, message.PeerID) + } + } + return nil +} + +func serverCheck(serverAddr string) bool { + rc, err := goricochet.Open(serverAddr) + if err == nil { + rc.Conn.Close() + return true + } + return false +} + +func TestCwtchPeerIntegration(t *testing.T) { + // Hide logging "noise" + log.SetOutput(ioutil.Discard) + + generatedKey := checkAndGenPrivateKey(keyfile) + + serverKey, err := utils.LoadPrivateKeyFromFile(keyfile) + if err != nil { + t.Error("Could not load server's key from %v", keyfile) + } + serverAddr, _ := utils.GetOnionAddress(serverKey) + + serverOnline := false + if ! generatedKey { + fmt.Printf("Checking if test server %v is online...\n", serverAddr) + serverOnline = serverCheck(serverAddr) + } + + if ! serverOnline { + // launch app + server := new(cwtchserver.Server) + fmt.Printf("No server found\nStarting cwtch server...\n") + go server.Run(keyfile) + + // let tor get established + fmt.Printf("Establishing Tor hidden service: %v...\n", serverAddr) + time.Sleep(time.Second * 60) + } else { + fmt.Printf("Found existing cwtch server %v, using for tests...\n", serverAddr) + } + + // launch alice + alice := peer.NewCwtchPeer("Alice") + groupId, invite := alice.Profile.StartGroup(serverAddr) + gci := &protocol.CwtchPeerPacket{} + proto.Unmarshal(invite, gci) + alice.Profile.AddContact(alice.Profile.Onion, &alice.Profile.PublicProfile) + fmt.Println("Alice joining group...") + alice.JoinServer(serverAddr) + + // launch bob + bob := peer.NewCwtchPeer("Bob") + bob.Profile.ProcessInvite(gci.GetGroupChatInvite(), serverAddr) + bob.Profile.AddContact(bob.Profile.Onion, &bob.Profile.PublicProfile) + fmt.Println("Bob joining group...") + bob.JoinServer(serverAddr) + + // Associate peer alice & bob as peers + alice.Profile.AddContact(bob.Profile.Onion, &bob.Profile.PublicProfile) + bob.Profile.AddContact(alice.Profile.Onion, &alice.Profile.PublicProfile) + + // Conversation + fmt.Println("Alice> ", aliceLines[0]) + alice.SendMessageToGroup(groupId, aliceLines[0]) + time.Sleep(time.Second * 2) + + fmt.Println("Bob> ", bobLines[0]) + bob.SendMessageToGroup(groupId, bobLines[0]) + time.Sleep(time.Second * 2) + + fmt.Println("Alice> ", aliceLines[1]) + alice.SendMessageToGroup(groupId, aliceLines[1]) + fmt.Println("Bob> ", bobLines[1]) + bob.SendMessageToGroup(groupId, bobLines[1]) + time.Sleep(time.Second * 2) + + fmt.Println("Alice> ", aliceLines[2]) + alice.SendMessageToGroup(groupId, aliceLines[2]) + // Todo: Alice disconnects + time.Sleep(time.Second * 2) + + fmt.Println("Bob> ", bobLines[2]) + bob.SendMessageToGroup(groupId, bobLines[2]) + time.Sleep(time.Second * 2) + + + // Todo: Alice reconects, gets missed messages (from bob) + + // Verify + + // final syncing time... + time.Sleep(time.Second * 2) + + alicesGroup := alice.Profile.Groups[groupId] + fmt.Printf("Alice TimeLine:\n") + printAndVerifyTimeline(t, alicesGroup.Timeline) + + bobsGroup := bob.Profile.Groups[groupId] + fmt.Printf("Bob TimeLine:\n") + printAndVerifyTimeline(t, bobsGroup.Timeline) + + if len(alicesGroup.Timeline.Messages) != 6 { + t.Errorf("Alice's timeline does not have all messages") + return + } + + // check message 0,1 and 4,5 for content (2,3 could be out of order) + if alicesGroup.Timeline.Messages[0].Message != aliceLines[0] || alicesGroup.Timeline.Messages[1].Message != bobLines[0] || + alicesGroup.Timeline.Messages[4].Message != aliceLines[2] || alicesGroup.Timeline.Messages[5].Message != bobLines[2] { + t.Errorf("Some of the messages did not have the expected content!") + } + + // Todo: shutdown users and server } diff --git a/testing/private_key b/testing/private_key deleted file mode 100644 index 40b9757..0000000 --- a/testing/private_key +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICXgIBAAKBgQC3xEJBH4oVFaotPJw6dezx67Gv4Xukw8CZRGqNFO8yF7Rejtcj -/0RTqqZwj6H6FjxY60dgYnN6IphW0juemNZhxOXeM/5Gb5xO+kWGi5Qt87aSDxnA -MDLgqw79ihuD3m1C1TBz0olmjXPU1VtadZuZcVBST7SLs2/k55GNNr7BoQIDAQAB -AoGBAK3ybVCdnSQWLM7DJ5LC23Wnx7sXceVlkiLCOyWuYjiFbatwBD/DupaD2yaD -HyzN7XOxyg93QZ2jr5XHTL30KEAn/3akNBsX3sjHZnjVfTwD5+oZKd7HYMMxekWf -87TIx2IHvGEo2NaFMLkEZ5TX3Gre8CYOofjFcpj4661ZfYp9AkEA9I0EmQX26ibs -CRGkwPuEj5q5N/PmIHgMWr1pepOlmzJjnxy6SI3NUwmzKrqM6YUM8loSywqfVMrJ -RVzA5jp76wJBAMBeu2hS8KcUTIu66j0pXMhI5wDA3yLiO53TEMwufCPXcaWUMH+e -5AIPL7aZ8ouf895OH0TZKxPNMnbrJ+5F0aMCQDoi/CDUxipMLnjJdP1bzdvF0Jp4 -pRC6+VTpCpZVW11V0VEWJ0LwUwuWlr1ls/If60ACIc2bLN2fh9Gxhzo0VRkCQQCS -nKCAVhYLgLEGHaLAknGgQ8+rB1QIphuBoYc/1n3OYzi+VT7RRSvJVgGrTZFJUNLw -LuIt+sWWBeHcOETqmFO5AkEAwwfcxs8QZtX6hCj2MTPi8Q28LIoA/M6eAqYc2I0B -eXxf2J2Qco7sMmBLr1Jp3jZNd5W2fMtlhUZAomOj4piVOA== ------END RSA PRIVATE KEY----- From 13eaa3a6846d4dcd9946896371383a9e44852707 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Thu, 3 May 2018 15:45:50 -0700 Subject: [PATCH 2/4] move server auto keygen to app/main --- server/app/main.go | 8 ++++---- server/server.go | 12 ------------ 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/server/app/main.go b/server/app/main.go index c1eb3cd..0e32724 100644 --- a/server/app/main.go +++ b/server/app/main.go @@ -11,14 +11,14 @@ import ( const privateKeyFile = "./private_key" func checkAndGenPrivateKey(privateKeyFile string) { - if _, err := os.Stat(privateKeyFile); os.IsNotExist(err) { + if _, err := os.Stat(privateKeyFile); os.IsNotExist(err) { log.Printf("no private key found!") log.Printf("generating new private key...") - pk, err := utils.GeneratePrivateKey() - if err != nil { + pk, pk_err := utils.GeneratePrivateKey() + if pk_err != nil { log.Fatalf("error generating new private key: %v\n", err) } - err = ioutil.WriteFile(privateKeyFile, []byte(utils.PrivateKeyToString(pk)), 0400) + err := ioutil.WriteFile(privateKeyFile, []byte(utils.PrivateKeyToString(pk)), 0400) if err != nil { log.Fatalf("error writing new private key to file %s: %v\n", privateKeyFile, err) } diff --git a/server/server.go b/server/server.go index b0063ba..70ac609 100644 --- a/server/server.go +++ b/server/server.go @@ -9,8 +9,6 @@ import ( "github.com/s-rah/go-ricochet/channels" "github.com/s-rah/go-ricochet/utils" "log" - "os" - "io/ioutil" ) // Server encapsulates a complete, compliant Cwtch server. @@ -23,16 +21,6 @@ type Server struct { func (s *Server) Run(privateKeyFile string) { cwtchserver := new(application.RicochetApplication) - if _, err := os.Stat(privateKeyFile); os.IsNotExist(err) { - log.Printf("no private key found!") - log.Printf("generating new private key...") - pk, pk_err := utils.GeneratePrivateKey() - if pk_err != nil { - log.Fatalf("error generating new private key: %v", err) - } - ioutil.WriteFile(privateKeyFile, []byte(utils.PrivateKeyToString(pk)), 0400) - } - pk, err := utils.LoadPrivateKeyFromFile(privateKeyFile) if err != nil { From 8e7cd9c04b37f09ae9a3466a3d33ccc72b57054e Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Sat, 5 May 2018 21:18:00 -0700 Subject: [PATCH 3/4] Adding sync around timeline, adding hooks for latency checks --- app/app.go | 1 - 1 file changed, 1 deletion(-) diff --git a/app/app.go b/app/app.go index b1899ee..a73348b 100644 --- a/app/app.go +++ b/app/app.go @@ -1,7 +1,6 @@ package app import ( - "git.mascherari.press/cwtch/model" "git.mascherari.press/cwtch/peer" "log" ) From af004e46413fdf23ca242caaaff323fc3367ef68 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Fri, 27 Apr 2018 12:20:33 -0700 Subject: [PATCH 4/4] expand integ test: - run own server; delete pk from repo - test now can use preexisting server if online (checks) - alice & bob users - chat - pretty print results - verify messages and content TODO: disconnect and reconnect to confirm offline delivery TODO: use preexisting test server --- .../cwtch_peer_server_intergration_test.go | 65 +++++++++++++++---- 1 file changed, 53 insertions(+), 12 deletions(-) diff --git a/testing/cwtch_peer_server_intergration_test.go b/testing/cwtch_peer_server_intergration_test.go index 9faae1d..0b66536 100644 --- a/testing/cwtch_peer_server_intergration_test.go +++ b/testing/cwtch_peer_server_intergration_test.go @@ -93,25 +93,48 @@ func TestCwtchPeerIntegration(t *testing.T) { } // launch alice + fmt.Println("Creating Alice...") alice := peer.NewCwtchPeer("Alice") - groupId, invite := alice.Profile.StartGroup(serverAddr) + alice.Profile.AddContact(alice.Profile.Onion, &alice.Profile.PublicProfile) + fmt.Println("Alice created:", alice.Profile.Onion) + + fmt.Println("Starting group on ", serverAddr, "...") + groupId, invite, err := alice.Profile.StartGroup(serverAddr) + fmt.Printf("Started group: %v!\n", groupId) + if err != nil { + t.Error("Failed to start group: %v", err) + return + } + gci := &protocol.CwtchPeerPacket{} proto.Unmarshal(invite, gci) - alice.Profile.AddContact(alice.Profile.Onion, &alice.Profile.PublicProfile) - fmt.Println("Alice joining group...") + + + fmt.Println("Alice joining server/group...") alice.JoinServer(serverAddr) // launch bob + fmt.Println("Creating Bob...") bob := peer.NewCwtchPeer("Bob") - bob.Profile.ProcessInvite(gci.GetGroupChatInvite(), serverAddr) bob.Profile.AddContact(bob.Profile.Onion, &bob.Profile.PublicProfile) - fmt.Println("Bob joining group...") - bob.JoinServer(serverAddr) + fmt.Println("Bob created:", bob.Profile.Onion) // Associate peer alice & bob as peers + fmt.Println("Peering Alice and Bob...") alice.Profile.AddContact(bob.Profile.Onion, &bob.Profile.PublicProfile) bob.Profile.AddContact(alice.Profile.Onion, &alice.Profile.PublicProfile) + // TODO: have alice actually protocolly send the invite + fmt.Printf("Bob processing invite to group %v\n", gci.GetGroupChatInvite().GroupName) + bob.Profile.ProcessInvite(gci.GetGroupChatInvite(), alice.Profile.Onion) + + fmt.Println("Bob joining server/group...") + bob.JoinServer(serverAddr) + + time.Sleep(time.Second * 10) + + + fmt.Println("Starting conversation in group...") // Conversation fmt.Println("Alice> ", aliceLines[0]) alice.SendMessageToGroup(groupId, aliceLines[0]) @@ -121,11 +144,12 @@ func TestCwtchPeerIntegration(t *testing.T) { bob.SendMessageToGroup(groupId, bobLines[0]) time.Sleep(time.Second * 2) + // "instant" - could be either order? fmt.Println("Alice> ", aliceLines[1]) alice.SendMessageToGroup(groupId, aliceLines[1]) fmt.Println("Bob> ", bobLines[1]) bob.SendMessageToGroup(groupId, bobLines[1]) - time.Sleep(time.Second * 2) + time.Sleep(time.Second * 3) fmt.Println("Alice> ", aliceLines[2]) alice.SendMessageToGroup(groupId, aliceLines[2]) @@ -142,15 +166,32 @@ func TestCwtchPeerIntegration(t *testing.T) { // Verify // final syncing time... - time.Sleep(time.Second * 2) + time.Sleep(time.Second * 4) + + alicesGroup := alice.Profile.GetGroupByGroupID(groupId) + fmt.Printf("alice Groups:\n") + for k := range alice.Profile.Groups { + fmt.Println(" " + k) + } + if alicesGroup == nil { + t.Error("aliceGroup == nil") + return + } - alicesGroup := alice.Profile.Groups[groupId] fmt.Printf("Alice TimeLine:\n") - printAndVerifyTimeline(t, alicesGroup.Timeline) + printAndVerifyTimeline(t, alicesGroup.GetTimeline()) - bobsGroup := bob.Profile.Groups[groupId] + bobsGroup := bob.Profile.GetGroupByGroupID(groupId) + fmt.Printf("bob Groups:\n") + for k := range bob.Profile.Groups { + fmt.Println(" " + k) + } + if bobsGroup == nil { + t.Error("bobGroup == nil") + return + } fmt.Printf("Bob TimeLine:\n") - printAndVerifyTimeline(t, bobsGroup.Timeline) + printAndVerifyTimeline(t, bobsGroup.GetTimeline()) if len(alicesGroup.Timeline.Messages) != 6 { t.Errorf("Alice's timeline does not have all messages")