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/testing/cwtch_peer_server_intergration_test.go b/testing/cwtch_peer_server_intergration_test.go index 697150d..0b66536 100644 --- a/testing/cwtch_peer_server_intergration_test.go +++ b/testing/cwtch_peer_server_intergration_test.go @@ -1,22 +1,208 @@ 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 + fmt.Println("Creating Alice...") + alice := peer.NewCwtchPeer("Alice") + 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) + + + fmt.Println("Alice joining server/group...") + alice.JoinServer(serverAddr) + + // launch bob + fmt.Println("Creating Bob...") + bob := peer.NewCwtchPeer("Bob") + bob.Profile.AddContact(bob.Profile.Onion, &bob.Profile.PublicProfile) + 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]) + time.Sleep(time.Second * 2) + + fmt.Println("Bob> ", bobLines[0]) + 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 * 3) + + 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 * 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 + } + + fmt.Printf("Alice TimeLine:\n") + printAndVerifyTimeline(t, alicesGroup.GetTimeline()) + + 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.GetTimeline()) + + 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-----