From 5f94e82347ff143f44c8079d1c4aeb4f9444ea85 Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Sat, 10 Mar 2018 13:26:19 -0800 Subject: [PATCH] PeerServerConnection Definition and Tests --- .gitignore | 1 + client/connections/peerserverconnection.go | 79 ++++++++++++++++++ .../connections/peerserverconnection_test.go | 81 +++++++++++++++++++ client/connections/state.go | 10 +++ client/cwtch_peer.go | 17 ++++ client/send/peer_send_channel.go | 5 +- client/send/peer_send_channel_test.go | 10 +-- protocol/spam/spamguard.go | 5 +- testing/private_key | 15 ++++ 9 files changed, 209 insertions(+), 14 deletions(-) create mode 100644 .gitignore create mode 100644 client/connections/peerserverconnection.go create mode 100644 client/connections/peerserverconnection_test.go create mode 100644 client/connections/state.go create mode 100644 testing/private_key diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f47cb20 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.out diff --git a/client/connections/peerserverconnection.go b/client/connections/peerserverconnection.go new file mode 100644 index 0000000..bcb2492 --- /dev/null +++ b/client/connections/peerserverconnection.go @@ -0,0 +1,79 @@ +package connections + +import ( + "github.com/s-rah/go-ricochet" + "github.com/s-rah/go-ricochet/connection" + "github.com/s-rah/go-ricochet/channels" + "github.com/s-rah/go-ricochet/identity" + "github.com/s-rah/go-ricochet/utils" + "git.mascherari.press/cwtch/client/send" + "git.mascherari.press/cwtch/protocol" + "time" +) + +type PeerServerConnection struct { + connection.AutoConnectionHandler + Server string + state ConnectionState + connection connection.Connection +} + +func NewPeerServerConnection(serverhostname string) *PeerServerConnection { + psc := new(PeerServerConnection) + psc.Server = serverhostname + psc.Init() + return psc +} + +// GetState returns the current connection state +func (psc *PeerServerConnection) GetState() ConnectionState { + return psc.state +} + +// Run manages the setup and teardown of a peer server connection +func (psc *PeerServerConnection) Run() error { + rc, err := goricochet.Open(psc.Server) + if err == nil { + psc.connection = *rc + psc.state = CONNECTED + pk, err := utils.GeneratePrivateKey() + if err == nil { + _, err := connection.HandleOutboundConnection(&psc.connection).ProcessAuthAsClient(identity.Initialize("cwtchpeer", pk)) + if err == nil { + psc.state = AUTHENTICATED + psc.connection.Process(psc) + } + } + } + return err +} + + +// Break makes Run() return and prevents processing, but doesn't close the connection. +func (psc *PeerServerConnection) Break() error { + return psc.connection.Break() +} + +func (psc *PeerServerConnection) SendGroupMessage(gm *protocol.GroupMessage) { + psc.connection.Do(func() error { + psc.connection.RequestOpenChannel("im.cwtch.server.send", &send.CwtchPeerSendChannel{}) + return nil + }) + // TODO We have to wait to receive the channel result before we can continue + // We should have a better mechanism for this kindof interaction + time.Sleep(time.Second * 1) + psc.connection.Do(func() error { + channel := psc.connection.Channel("im.cwtch.server.send", channels.Outbound) + if channel != nil { + sendchannel, ok := channel.Handler.(*send.CwtchPeerSendChannel) + if ok { + sendchannel.SendGroupMessage(gm) + } + } + return nil + }) +} + +func (psc *PeerServerConnection) HandleGroupMessage(*protocol.GroupMessage) { + +} diff --git a/client/connections/peerserverconnection_test.go b/client/connections/peerserverconnection_test.go new file mode 100644 index 0000000..121af53 --- /dev/null +++ b/client/connections/peerserverconnection_test.go @@ -0,0 +1,81 @@ +package connections + +import ( + "crypto/rsa" + "github.com/s-rah/go-ricochet" + "github.com/s-rah/go-ricochet/connection" + "github.com/s-rah/go-ricochet/identity" + "github.com/s-rah/go-ricochet/utils" + "github.com/s-rah/go-ricochet/channels" + "git.mascherari.press/cwtch/server/send" + "git.mascherari.press/cwtch/protocol" + "net" + "testing" + "time" +) + +func ServerAuthValid(hostname string, publicKey rsa.PublicKey) (allowed, known bool) { + return true, true +} + +type TestServer struct { + connection.AutoConnectionHandler + Received bool +} + +func (ts *TestServer) HandleGroupMessage(gm *protocol.GroupMessage) { + ts.Received = true +} + +func runtestserver(t *testing.T, ts *TestServer) { + ln, _ := net.Listen("tcp", "127.0.0.1:5451") + conn, _ := ln.Accept() + defer conn.Close() + privateKey, err := utils.LoadPrivateKeyFromFile("../../testing/private_key") + if err != nil { + t.Errorf("Private Key Error %v", err) + } + rc, err := goricochet.NegotiateVersionInbound(conn) + if err != nil { + t.Errorf("Negotiate Version Error: %v", err) + } + err = connection.HandleInboundConnection(rc).ProcessAuthAsServer(identity.Initialize("", privateKey), ServerAuthValid) + if err != nil { + t.Errorf("ServerAuth Error: %v", err) + } + + + ts.RegisterChannelHandler("im.cwtch.server.send", func() channels.Handler { + server := new(send.CwtchServerSendChannel) + server.Handler = ts + return server + }) + + rc.Process(ts) +} + +func TestPeerServerConnection(t *testing.T) { + ts := new(TestServer) + ts.Init() + go runtestserver(t, ts) + psc := NewPeerServerConnection("127.0.0.1:5451|kwke2hntvyfqm7dr") + state := psc.GetState() + if state != DISCONNECTED { + t.Errorf("new connections should start in disconnected state") + } + time.Sleep(time.Second * 1) + go psc.Run() + time.Sleep(time.Second * 2) + state = psc.GetState() + if state != AUTHENTICATED { + t.Errorf("connection should now be authed(%v), instead was %v", AUTHENTICATED, state) + } + + gm := &protocol.GroupMessage{Ciphertext: []byte("hello")} + psc.SendGroupMessage(gm) + time.Sleep(time.Second * 2) + if ts.Received == false { + t.Errorf("Should have received a group message in test server") + } + +} diff --git a/client/connections/state.go b/client/connections/state.go new file mode 100644 index 0000000..42b5a20 --- /dev/null +++ b/client/connections/state.go @@ -0,0 +1,10 @@ +package connections + +type ConnectionState int + +const ( + DISCONNECTED ConnectionState = iota + CONNECTING + CONNECTED + AUTHENTICATED +) diff --git a/client/cwtch_peer.go b/client/cwtch_peer.go index 0ec1f00..bb4c9ab 100644 --- a/client/cwtch_peer.go +++ b/client/cwtch_peer.go @@ -13,6 +13,20 @@ import ( "sync" ) +/** +ServerConnectionPool + background thread running Process() + pointer to connection + Probably worthwhile defining a type called PeerServerConnection to manage background() and other commmands! + +PeerConnectionPool + Background thread running Process() + Pointer to connections + +Move CwtchPeerChannel under peer/ + Write tests for Peer Channel +*/ + type CwtchPeerInstance struct { rai *application.ApplicationInstance ra *application.RicochetApplication @@ -173,3 +187,6 @@ func (cph *CwtchPeerHandler) ClientIdentity(ci *protocol.CwtchIdentity) { func (cph *CwtchPeerHandler) HandleGroupInvite() { } + +func (cph *CwtchPeerHandler) HandleGroupMessage(gm *protocol.GroupMessage) { +} diff --git a/client/send/peer_send_channel.go b/client/send/peer_send_channel.go index 2cce769..6e6d88e 100644 --- a/client/send/peer_send_channel.go +++ b/client/send/peer_send_channel.go @@ -1,4 +1,4 @@ -package listen +package send import ( "errors" @@ -67,6 +67,7 @@ func (cplc *CwtchPeerSendChannel) OpenOutboundResult(err error, crm *Protocol_Da cplc.channel.Pending = false ce, _ := proto.GetExtension(crm, protocol.E_ServerNonce) cplc.challenge = ce.([]byte)[:] + } } } @@ -74,7 +75,7 @@ func (cplc *CwtchPeerSendChannel) OpenOutboundResult(err error, crm *Protocol_Da // SendGroupMessage performs the spamguard proof of work and sends a message. func (cplc *CwtchPeerSendChannel) SendGroupMessage(gm *protocol.GroupMessage) { sgsolve := cplc.spamGuard.SolveChallenge(cplc.challenge, gm.GetCiphertext()) - gm.Spamguard = sgsolve + gm.Spamguard = sgsolve[:] csp := &protocol.CwtchServerPacket{ GroupMessage: gm, } diff --git a/client/send/peer_send_channel_test.go b/client/send/peer_send_channel_test.go index e09535c..edf13a4 100644 --- a/client/send/peer_send_channel_test.go +++ b/client/send/peer_send_channel_test.go @@ -1,4 +1,4 @@ -package listen +package send import ( "git.mascherari.press/cwtch/protocol" @@ -9,14 +9,6 @@ import ( "testing" ) -type TestHandler struct { - Received bool -} - -func (th *TestHandler) HandleGroupMessage(m *protocol.GroupMessage) { - th.Received = true -} - func TestPeerSendChannelAttributes(t *testing.T) { cssc := new(CwtchPeerSendChannel) if cssc.Type() != "im.cwtch.server.send" { diff --git a/protocol/spam/spamguard.go b/protocol/spam/spamguard.go index 534da09..5685037 100644 --- a/protocol/spam/spamguard.go +++ b/protocol/spam/spamguard.go @@ -15,7 +15,6 @@ type SpamGuard struct { nonce [24]byte } - //GenerateChallenge returns a channel result packet with a spamguard challenge nonce func (sg *SpamGuard) GenerateChallenge(channelID int32) []byte { @@ -75,8 +74,8 @@ func (sg *SpamGuard) SolveChallenge(challenge []byte, message []byte) []byte { // ValidateChallenge returns true if the message and spamguard pass the challenge func (sg *SpamGuard) ValidateChallenge(message []byte, spamguard []byte) bool { if len(spamguard) != 24 { - return false - } + return false + } solve := make([]byte, len(sg.nonce)+len(message)+len(spamguard)) copy(solve[0:], sg.nonce[:]) copy(solve[len(sg.nonce):], message[:]) diff --git a/testing/private_key b/testing/private_key new file mode 100644 index 0000000..40b9757 --- /dev/null +++ b/testing/private_key @@ -0,0 +1,15 @@ +-----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-----