diff --git a/model/profile.go b/model/profile.go index 4b3e9c9..2145e5f 100644 --- a/model/profile.go +++ b/model/profile.go @@ -93,7 +93,10 @@ func (p *Profile) StartGroup(server string) (groupID string, invite []byte) { GroupSharedKey: group.GroupKey[:], ServerHost: server, } - invite, err := proto.Marshal(gci) + cp := &protocol.CwtchPeerPacket{ + GroupChatInvite: gci, + } + invite, err := proto.Marshal(cp) utils.CheckError(err) return } diff --git a/model/profile_test b/model/profile_test index 5012e2c..42a6feb 100644 --- a/model/profile_test +++ b/model/profile_test @@ -1 +1 @@ -{"Name":"Sarah","Ed25519PublicKey":"a8pgrWp2v1IIQCyULC2iu1qL1drQ5t2U6IWP8StQbgQ=","Contacts":{},"Ed25519PrivateKey":"prCl0X2vmZf7Mk3llqvFtdorNumzHnGnD4jm3QMuSxZrymCtana/UghALJQsLaK7WovV2tDm3ZTohY/xK1BuBA==","OnionPrivateKey":{"N":131068731621357493720072929300222638098708595317493690917455701844894949969712456924415904360558466676729758490034054382690670564021915749623913489576811414808490682341447683428107033511871993975442547751364987326228375564356319863018740191894673856750381991533992750928853175751258987424504305668829389370781,"E":65537,"D":2627894370362753051683412867547988868298870779058954634260597711585699135758459624314242310904890751990828122372167591724606575234215745227975377653904361946969317142822427004567032046170712030718609055500182294452975841610151524604548863606200879307458625483418780389791138043842317728008422567429265129217,"Primes":[10788225097346971746043305034916905885872150156656727758248727746432901839298229013945049979389606656460780955780310528453022789715728380260987737082720253,12149239605094054781678325910916206629901461735333362155233083066169807219934646408991015480595627046734476920828757029582713785879808385848485040747462177],"Precomputed":{"Dp":5173284558864813480368386519558930089496071882650273635633043424129069168616589761833026926808934928248057785637240321920337324143555484786640548290258165,"Dq":6738186996138955142964184967422712034173952594044540452239377806264250008852778242428024332647052075845778218689956215744884274366529978620027377833723777,"Qinv":5251104905219058958861116066024964644816198404536226338388786686281405794213358346986237142459566456065203273657491361435682285121728843067653981338100228,"CRTValues":[]}},"Groups":{}} \ No newline at end of file +{"Name":"Sarah","Ed25519PublicKey":"msKO36i2l86zvEL175TKZEC0nD73g2v7nV5xmK0Vphk=","Contacts":{},"Ed25519PrivateKey":"gY02OGDQrUZmtgrGE8Vc75m+YpveuiBnq7S04R6hDheawo7fqLaXzrO8QvXvlMpkQLScPveDa/udXnGYrRWmGQ==","OnionPrivateKey":{"N":149473818603978520797265583326345889632722230289009522405338669742795723417758103856403611357040387558433860451515052572608570172648790617938713499325164649087791083575310232535396589977906388592625399123963785709861980287466698616117387601534139103746310242068634673611193675737864910207364356589966194353473,"E":65537,"D":86372179235129264119389774334631106709052761967206167714270952639877840698086567786777007829029700426291870169505394524080848260344686218492440609418252045928103604805029397268780872419743985198533279610220673486415102569608190490192041308974054759325240302029165831212246096675348836655257812290267217972353,"Primes":[12798859654138079143364344404787850219664210052105976906571980247193551352543964631210504198681240048855374604305718740175510657834512957821516486884913417,11678682526661756792661834016830595869008788319138001870469300096518673413667724031509428867627103613547399458382675739150139741094498852501694360147458169],"Precomputed":{"Dp":8019280314598958509909975651827265416025626094719436802334028486053813863764176261522451957069254926623865104850782437826372799222707868639469788073228857,"Dq":8119140840742831728447418732545517936185336731870022143557414147696473718258828483507523964582237435959024888579450875492602146630873502261046407938088241,"Qinv":1212466450879442551713910248017765796626002260907864986369164997419826127998002105201194295184151193998884696413793530693071388392214893165411485014542824,"CRTValues":[]}},"Groups":{}} \ No newline at end of file diff --git a/model/profile_test.go b/model/profile_test.go index eccf079..fdb7732 100644 --- a/model/profile_test.go +++ b/model/profile_test.go @@ -29,7 +29,7 @@ func TestProfileIdentity(t *testing.T) { if err != nil { t.Errorf("alice should have added sarah as a contact %v", err) } - alice.AddCwtchIdentity("sarah.onion", *ci) + alice.AddCwtchIdentity("sarah.onion", ci) if alice.Contacts["sarah.onion"].Name != "Sarah" { t.Errorf("alice should have added sarah as a contact %v", alice.Contacts) } diff --git a/peer/connections/peerpeerconnection_test.go b/peer/connections/peerpeerconnection_test.go index 6c6f19d..1fb6b14 100644 --- a/peer/connections/peerpeerconnection_test.go +++ b/peer/connections/peerpeerconnection_test.go @@ -2,24 +2,24 @@ package connections import ( "crypto/rsa" + "git.mascherari.press/cwtch/model" + "git.mascherari.press/cwtch/peer/peer" + "git.mascherari.press/cwtch/protocol" "github.com/s-rah/go-ricochet" + "github.com/s-rah/go-ricochet/channels" "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" "net" "testing" "time" - "git.mascherari.press/cwtch/model" - "git.mascherari.press/cwtch/protocol" - "git.mascherari.press/cwtch/peer/peer" ) func PeerAuthValid(hostname string, publicKey rsa.PublicKey) (allowed, known bool) { return true, true } -func runtestpeer(t *testing.T,tp *TestPeer) { +func runtestpeer(t *testing.T, tp *TestPeer) { ln, _ := net.Listen("tcp", "127.0.0.1:5452") conn, _ := ln.Accept() defer conn.Close() @@ -42,23 +42,40 @@ func runtestpeer(t *testing.T,tp *TestPeer) { return peer }) + go func() { + alice := model.GenerateNewProfile("alice") + time.Sleep(time.Second * 1) + rc.Do(func() error { + channel := rc.Channel("im.cwtch.peer", channels.Inbound) + if channel != nil { + peerchannel, ok := channel.Handler.(*peer.CwtchPeerChannel) + if ok { + peerchannel.SendMessage(alice.GetCwtchIdentityPacket()) + } + } + return nil + }) + }() + rc.Process(tp) } type TestPeer struct { - connection.AutoConnectionHandler - ReceivedIdentityPacket bool + connection.AutoConnectionHandler + ReceivedIdentityPacket bool + ReceivedGroupInvite bool } func (tp *TestPeer) ClientIdentity(ci *protocol.CwtchIdentity) { - tp.ReceivedIdentityPacket = true + tp.ReceivedIdentityPacket = true } func (tp *TestPeer) HandleGroupInvite(gci *protocol.GroupChatInvite) { + tp.ReceivedGroupInvite = true } func TestPeerPeerConnection(t *testing.T) { - profile := model.GenerateNewProfile("sarah") + profile := model.GenerateNewProfile("sarah") ppc := NewPeerPeerConnection("127.0.0.1:5452|kwke2hntvyfqm7dr", profile) //numcalls := 0 tp := new(TestPeer) @@ -74,8 +91,16 @@ func TestPeerPeerConnection(t *testing.T) { if state != AUTHENTICATED { t.Errorf("connection state should be authenticated(3), was instead %v", state) } - + if tp.ReceivedIdentityPacket == false { - t.Errorf("should have received an identity packet") + t.Errorf("should have received an identity packet") } + + _, invite := profile.StartGroup("aaa.onion") + ppc.SendGroupInvite(invite) + time.Sleep(time.Second * 3) + if tp.ReceivedGroupInvite == false { + t.Errorf("should have received an group invite packet") + } + } diff --git a/peer/connections/peerserverconnection.go b/peer/connections/peerserverconnection.go index ba20359..4249ce9 100644 --- a/peer/connections/peerserverconnection.go +++ b/peer/connections/peerserverconnection.go @@ -2,6 +2,7 @@ package connections import ( "git.mascherari.press/cwtch/peer/fetch" + "git.mascherari.press/cwtch/peer/listen" "git.mascherari.press/cwtch/peer/send" "git.mascherari.press/cwtch/protocol" "github.com/s-rah/go-ricochet" @@ -51,6 +52,11 @@ func (psc *PeerServerConnection) Run() error { psc.connection.RequestOpenChannel("im.cwtch.server.fetch", &fetch.CwtchPeerFetchChannel{Handler: psc}) return nil }) + + psc.connection.Do(func() error { + psc.connection.RequestOpenChannel("im.cwtch.server.listen", &listen.CwtchPeerListenChannel{Handler: psc}) + return nil + }) }() psc.connection.Process(psc) diff --git a/peer/cwtch_peer.go b/peer/cwtch_peer.go index eafbb75..f01be61 100644 --- a/peer/cwtch_peer.go +++ b/peer/cwtch_peer.go @@ -3,12 +3,12 @@ package peer import ( "encoding/json" "git.mascherari.press/cwtch/model" + "git.mascherari.press/cwtch/peer/connections" + "git.mascherari.press/cwtch/peer/peer" "git.mascherari.press/cwtch/protocol" - "github.com/s-rah/go-ricochet" "github.com/s-rah/go-ricochet/application" "github.com/s-rah/go-ricochet/channels" "github.com/s-rah/go-ricochet/connection" - "github.com/s-rah/go-ricochet/identity" "io/ioutil" "sync" ) @@ -35,11 +35,13 @@ func (cpi *CwtchPeerInstance) Init(rai *application.ApplicationInstance, ra *app type CwtchPeer struct { connection.AutoConnectionHandler - Profile *model.Profile - PendingContacts []string - PendingInvites map[string][]string - mutex sync.Mutex - Log chan string `json:"-"` + Profile *model.Profile + PendingContacts []string + PendingInvites map[string][]string + mutex sync.Mutex + Log chan string `json:"-"` + peerconnections map[string]*connections.PeerPeerConnection + serverconnections map[string]*connections.PeerServerConnection } func NewCwtchPeer(name string) *CwtchPeer { @@ -47,13 +49,15 @@ func NewCwtchPeer(name string) *CwtchPeer { peer.Profile = model.GenerateNewProfile(name) peer.PendingInvites = make(map[string][]string) peer.Log = make(chan string) + peer.peerconnections = make(map[string]*connections.PeerPeerConnection) + peer.serverconnections = make(map[string]*connections.PeerServerConnection) peer.Init() return peer } func (cp *CwtchPeer) Save(profilefile string) error { cp.mutex.Lock() - bytes,_ := json.Marshal(cp) + bytes, _ := json.Marshal(cp) err := ioutil.WriteFile(profilefile, bytes, 0600) cp.mutex.Unlock() return err @@ -81,10 +85,6 @@ func (cp *CwtchPeer) InviteOnionToGroup(onion string, groupid string) { cp.mutex.Unlock() } -func (cp *CwtchPeer) PeerListen(onion string) { - -} - func (cp *CwtchPeer) JoinServer(onion string) { } @@ -110,9 +110,9 @@ func (cp *CwtchPeer) Listen() error { cpi := new(CwtchPeerInstance) cpi.Init(rai, cwtchpeer) return func() channels.Handler { - chat := new(protocol.CwtchPeerChannel) - chat.Handler = &CwtchPeerHandler{Onion: rai.RemoteHostname, Peer: cp} - return chat + cpc := new(peer.CwtchPeerChannel) + cpc.Handler = &CwtchPeerHandler{Onion: rai.RemoteHostname, Peer: cp} + return cpc } }) @@ -123,52 +123,7 @@ func (cp *CwtchPeer) Listen() error { } func (cp *CwtchPeer) EstablishContact(onion string) { - rc, err := goricochet.Open(onion) - if err == nil { - cp.Log <- "Connected to " + onion - - cp.RegisterChannelHandler("im.cwtch.peer", func() channels.Handler { - peer := new(protocol.CwtchPeerChannel) - peer.Handler = &CwtchPeerHandler{Onion: onion, Peer: cp} - return peer - }) - - if err == nil { - _, err := connection.HandleOutboundConnection(rc).ProcessAuthAsClient(identity.Initialize("", cp.Profile.OnionPrivateKey)) - if err == nil { - cp.Log <- "Authed to " + onion - - go func() { - rc.Do(func() error { - rc.RequestOpenChannel("im.cwtch.peer", &protocol.CwtchPeerChannel{ - Handler: &CwtchPeerHandler{Onion: onion, Peer: cp}, - }) - return nil - }) - - sendIdentity := func(message []byte) { - rc.Do(func() error { - channel := rc.Channel("im.cwtch.peer", channels.Outbound) - if channel != nil { - cwtchchannel, ok := channel.Handler.(*protocol.CwtchPeerChannel) - if ok { - cwtchchannel.SendMessage(message) - } - } else { - cp.Log <- "Error finding cwtch channel " + onion - } - return nil - }) - } - sendIdentity(cp.Profile.GetCwtchIdentityPacket()) - }() - rc.Process(cp) - } - } - } - // onion is offline - // TODO Sleep, Wake, Retry (assuming contact still exists) } type CwtchPeerHandler struct { @@ -178,10 +133,11 @@ type CwtchPeerHandler struct { func (cph *CwtchPeerHandler) ClientIdentity(ci *protocol.CwtchIdentity) { cph.Peer.Log <- "Received Client Identity from " + cph.Onion + " " + ci.String() - cph.Peer.Profile.AddCwtchIdentity(cph.Onion, *ci) + cph.Peer.Profile.AddCwtchIdentity(cph.Onion, ci) } -func (cph *CwtchPeerHandler) HandleGroupInvite() { +func (cph *CwtchPeerHandler) HandleGroupInvite(gci *protocol.GroupChatInvite) { + cph.Peer.Profile.ProcessInvite(gci) } func (cph *CwtchPeerHandler) HandleGroupMessage(gm *protocol.GroupMessage) { diff --git a/peer/cwtch_peer_test.go b/peer/cwtch_peer_test.go index c667cd2..769b58e 100644 --- a/peer/cwtch_peer_test.go +++ b/peer/cwtch_peer_test.go @@ -5,11 +5,13 @@ import ( ) func TestCwtchPeerGenerate(t *testing.T) { - sarah := NewCwtchPeer("sarah") - sarah.Save("./test_profile") - sarahLoaded, err := LoadCwtchPeer("./test_profile") - if err != nil || sarahLoaded.Profile.Name != "sarah" { - t.Errorf("something went wrong saving and loading profiles %v %v", err, sarahLoaded) + + alice := NewCwtchPeer("alice") + alice.Save("./test_profile") + + aliceLoaded, err := LoadCwtchPeer("./test_profile") + if err != nil || aliceLoaded.Profile.Name != "alice" { + t.Errorf("something went wrong saving and loading profiles %v %v", err, aliceLoaded) } - //t.Logf("%v", sarahLoaded) + } diff --git a/peer/fetch/peer_fetch_channel_test.go b/peer/fetch/peer_fetch_channel_test.go index ebf1e13..e47aa87 100644 --- a/peer/fetch/peer_fetch_channel_test.go +++ b/peer/fetch/peer_fetch_channel_test.go @@ -54,6 +54,8 @@ func TestPeerFetchChannel(t *testing.T) { pfc.Handler = th channel := new(channels.Channel) channel.ID = 3 + channel.SendMessage = func([]byte) {} + channel.CloseChannel = func() {} result, err := pfc.OpenOutbound(channel) if err != nil { t.Errorf("expected result but also got non-nil error: result:%v, err: %v", result, err) diff --git a/peer/peer/peer_channel.go b/peer/peer/peer_channel.go index 2544814..271330d 100644 --- a/peer/peer/peer_channel.go +++ b/peer/peer/peer_channel.go @@ -100,7 +100,7 @@ func (cpc *CwtchPeerChannel) Packet(data []byte) { if cpp.GetCwtchIdentify() != nil { cpc.Handler.ClientIdentity(cpp.GetCwtchIdentify()) } else if cpp.GetGroupChatInvite() != nil { - cpc.Handler.HandleGroupInvite(cpp.GetGroupChatInvite()) + cpc.Handler.HandleGroupInvite(cpp.GetGroupChatInvite()) } } } diff --git a/protocol/channel.go b/protocol/channel.go deleted file mode 100644 index 751f3ba..0000000 --- a/protocol/channel.go +++ /dev/null @@ -1,103 +0,0 @@ -package protocol - -import ( - "github.com/golang/protobuf/proto" - "github.com/s-rah/go-ricochet/channels" - "github.com/s-rah/go-ricochet/utils" - "github.com/s-rah/go-ricochet/wire/control" -) - -// CwtchPeerChannel implements the ChannelHandler interface for a channel of -// type "im.ricochet.Cwtch". The channel may be inbound or outbound. -// -// CwtchPeerChannel implements protocol-level sanity and state validation, but -// does not handle or acknowledge Cwtch messages. The application must provide -// a CwtchPeerChannelHandler implementation to handle Cwtch events. -type CwtchPeerChannel struct { - // Methods of Handler are called for Cwtch events on this channel - Handler CwtchPeerChannelHandler - channel *channels.Channel -} - -// CwtchPeerChannelHandler is implemented by an application type to receive -// events from a CwtchPeerChannel. -type CwtchPeerChannelHandler interface { - ClientIdentity(*CwtchIdentity) - HandleGroupInvite() -} - -// Type returns the type string for this channel, e.g. "im.ricochet.Cwtch". -func (cpc *CwtchPeerChannel) SendMessage(data []byte) { - cpc.channel.SendMessage(data) -} - -// Type returns the type string for this channel, e.g. "im.ricochet.Cwtch". -func (cpc *CwtchPeerChannel) Type() string { - return "im.cwtch.peer" -} - -// Closed is called when the channel is closed for any reason. -func (cpc *CwtchPeerChannel) Closed(err error) { - -} - -// OnlyClientCanOpen - for Cwtch channels any side can open -func (cpc *CwtchPeerChannel) OnlyClientCanOpen() bool { - return false -} - -// Singleton - for Cwtch channels there can only be one instance per direction -func (cpc *CwtchPeerChannel) Singleton() bool { - return true -} - -// Bidirectional - for Cwtch channels are not bidrectional -func (cpc *CwtchPeerChannel) Bidirectional() bool { - return false -} - -// RequiresAuthentication - Cwtch channels require hidden service auth -func (cpc *CwtchPeerChannel) RequiresAuthentication() string { - return "im.ricochet.auth.hidden-service" -} - -// OpenInbound is the first method called for an inbound channel request. -// If an error is returned, the channel is rejected. If a RawMessage is -// returned, it will be sent as the ChannelResult message. -func (cpc *CwtchPeerChannel) OpenInbound(channel *channels.Channel, raw *Protocol_Data_Control.OpenChannel) ([]byte, error) { - cpc.channel = channel - messageBuilder := new(utils.MessageBuilder) - return messageBuilder.AckOpenChannel(channel.ID), nil -} - -// OpenOutbound is the first method called for an outbound channel request. -// If an error is returned, the channel is not opened. If a RawMessage is -// returned, it will be sent as the OpenChannel message. -func (cpc *CwtchPeerChannel) OpenOutbound(channel *channels.Channel) ([]byte, error) { - cpc.channel = channel - messageBuilder := new(utils.MessageBuilder) - return messageBuilder.OpenChannel(channel.ID, cpc.Type()), nil -} - -// OpenOutboundResult is called when a response is received for an -// outbound OpenChannel request. If `err` is non-nil, the channel was -// rejected and Closed will be called immediately afterwards. `raw` -// contains the raw protocol message including any extension data. -func (cpc *CwtchPeerChannel) OpenOutboundResult(err error, crm *Protocol_Data_Control.ChannelResult) { - if err == nil { - if crm.GetOpened() { - cpc.channel.Pending = false - } - } -} - -// Packet is called for each raw packet received on this channel. -func (cpc *CwtchPeerChannel) Packet(data []byte) { - cpp := &CwtchPeerPacket{} - err := proto.Unmarshal(data, cpp) - if err == nil { - if cpp.GetCwtchIdentify() != nil { - cpc.Handler.ClientIdentity(cpp.GetCwtchIdentify()) - } - } -}