From ad9d0efb02941312895197ab2c89a77f936186b9 Mon Sep 17 00:00:00 2001 From: erinn Date: Thu, 25 Oct 2018 19:20:58 -0700 Subject: [PATCH 1/2] updating chatchannels and echobot to use v3 --- .../examples/echobot-deprecated/main.go | 90 +++++++++++++ application/examples/echobot/main.go | 126 +++++++++++++++++- channels/chatchannel.go | 2 +- 3 files changed, 211 insertions(+), 7 deletions(-) create mode 100644 application/examples/echobot-deprecated/main.go diff --git a/application/examples/echobot-deprecated/main.go b/application/examples/echobot-deprecated/main.go new file mode 100644 index 0000000..457af6f --- /dev/null +++ b/application/examples/echobot-deprecated/main.go @@ -0,0 +1,90 @@ +package main + +import ( + "git.openprivacy.ca/openprivacy/libricochet-go/application" + "git.openprivacy.ca/openprivacy/libricochet-go/channels" + "git.openprivacy.ca/openprivacy/libricochet-go/utils" + "log" + "time" +) + +type EchoBotInstance struct { + rai *application.ApplicationInstance + ra *application.RicochetApplication +} + +func (ebi *EchoBotInstance) Init(rai *application.ApplicationInstance, ra *application.RicochetApplication) { + ebi.rai = rai + ebi.ra = ra +} + +// We always want bidirectional chat channels +func (ebi *EchoBotInstance) OpenInbound() { + log.Println("OpenInbound() ChatChannel handler called...") + outboutChatChannel := ebi.rai.Connection.Channel("im.ricochet.chat", channels.Outbound) + if outboutChatChannel == nil { + ebi.rai.Connection.Do(func() error { + ebi.rai.Connection.RequestOpenChannel("im.ricochet.chat", + &channels.ChatChannel{ + Handler: ebi, + }) + return nil + }) + } +} + +func (ebi *EchoBotInstance) ChatMessage(messageID uint32, when time.Time, message string) bool { + log.Printf("message from %v - %v", ebi.rai.RemoteHostname, message) + go ebi.ra.Broadcast(func(rai *application.ApplicationInstance) { + ebi.SendChatMessage(rai, ebi.rai.RemoteHostname+" "+message) + }) + return true +} + +func (ebi *EchoBotInstance) ChatMessageAck(messageID uint32, accepted bool) { + +} + +func (ebi *EchoBotInstance) SendChatMessage(rai *application.ApplicationInstance, message string) { + rai.Connection.Do(func() error { + channel := rai.Connection.Channel("im.ricochet.chat", channels.Outbound) + if channel != nil { + chatchannel, ok := channel.Handler.(*channels.ChatChannel) + if ok { + chatchannel.SendMessage(message) + } + } + return nil + }) +} + +func main() { + echobot := new(application.RicochetApplication) + pk, err := utils.LoadPrivateKeyFromFile("./testing/private_key") + + if err != nil { + log.Fatalf("error reading private key file: %v", err) + } + + l, err := application.SetupOnion("127.0.0.1:9051", "tcp4", "", pk, 9878) + + if err != nil { + log.Fatalf("error setting up onion service: %v", err) + } + + af := application.ApplicationInstanceFactory{} + af.Init() + af.AddHandler("im.ricochet.chat", func(rai *application.ApplicationInstance) func() channels.Handler { + ebi := new(EchoBotInstance) + ebi.Init(rai, echobot) + return func() channels.Handler { + chat := new(channels.ChatChannel) + chat.Handler = ebi + return chat + } + }) + + echobot.Init("echobot", pk, af, new(application.AcceptAllContactManager)) + log.Printf("echobot listening on %s", l.Addr().String()) + echobot.Run(l) +} diff --git a/application/examples/echobot/main.go b/application/examples/echobot/main.go index 457af6f..d1af675 100644 --- a/application/examples/echobot/main.go +++ b/application/examples/echobot/main.go @@ -3,9 +3,14 @@ package main import ( "git.openprivacy.ca/openprivacy/libricochet-go/application" "git.openprivacy.ca/openprivacy/libricochet-go/channels" - "git.openprivacy.ca/openprivacy/libricochet-go/utils" + "golang.org/x/crypto/ed25519" "log" "time" + "crypto/rand" + "git.openprivacy.ca/openprivacy/libricochet-go/utils" + "git.openprivacy.ca/openprivacy/libricochet-go/identity" + "git.openprivacy.ca/openprivacy/libricochet-go" + "git.openprivacy.ca/openprivacy/libricochet-go/connection" ) type EchoBotInstance struct { @@ -59,14 +64,18 @@ func (ebi *EchoBotInstance) SendChatMessage(rai *application.ApplicationInstance } func main() { + //////////// + // SERVER // + //////////// + echobot := new(application.RicochetApplication) - pk, err := utils.LoadPrivateKeyFromFile("./testing/private_key") + cpubk, cprivk, err := ed25519.GenerateKey(rand.Reader) if err != nil { - log.Fatalf("error reading private key file: %v", err) + log.Fatalf("error generating random key: %v", err) } - l, err := application.SetupOnion("127.0.0.1:9051", "tcp4", "", pk, 9878) + l, err := application.SetupOnionV3("127.0.0.1:9051", "tcp4", "", cprivk, utils.GetTorV3Hostname(cpubk), 9878) if err != nil { log.Fatalf("error setting up onion service: %v", err) @@ -84,7 +93,112 @@ func main() { } }) - echobot.Init("echobot", pk, af, new(application.AcceptAllContactManager)) + echobot.InitV3("echobot", identity.InitializeV3("echobot", &cprivk, &cpubk), af, new(application.AcceptAllContactManager)) log.Printf("echobot listening on %s", l.Addr().String()) - echobot.Run(l) + go echobot.Run(l) + + log.Printf("counting to five...") + time.Sleep(time.Second * 5) + + //////////// + // CLIENT // + //////////// + + //alicebot should nominally be in another package to prevent initializing it directly + alice := NewAliceBot(l.Addr().String()[:56]) + alice.SendMessage("be gay") + alice.SendMessage("do crime") + + // stick around and see what happens + time.Sleep(time.Second * 30) } + + +func NewAliceBot(onion string) alicebot { + alice := alicebot{} + alice.messages = make(map[uint32]string) + + var err error + alice.pub, alice.priv, err = ed25519.GenerateKey(rand.Reader) + if err != nil { + log.Fatalf("[alice] error generating key: %v", err) + } + + rc, err := goricochet.Open(onion) + if err != nil { + log.Fatalf("[alice] error connecting to echobot: %v", err) + } + + rc.TraceLog(false) + _, err = connection.HandleOutboundConnection(rc).ProcessAuthAsV3Client(identity.InitializeV3("alice", &alice.priv, &alice.pub)) + if err != nil { + log.Fatalf("[alice] failed to authenticate connection: %v", err) + } + + alice.rc = rc + + ach := connection.AutoConnectionHandler{} + ach.Init() + + ach.RegisterChannelHandler("im.ricochet.chat", func() channels.Handler { + chat := new(channels.ChatChannel) + chat.Handler = &alice + return chat + }) + + go alice.rc.Process(&ach) + + log.Printf("[alice] requesting channel...") + alice.rc.Do(func() error { + chatchannel := channels.ChatChannel{} + chatchannel.Handler = &alice + + _, err := alice.rc.RequestOpenChannel("im.ricochet.chat", &chatchannel) + if err != nil { + log.Fatalf("failed requestopenchannel: %v", err) + } + return nil + }) + + return alice +} + +type alicebot struct { + messages map[uint32]string + pub ed25519.PublicKey + priv ed25519.PrivateKey + mID int + rc *connection.Connection +} + +func (this *alicebot) SendMessage(message string) { + log.Printf("[alice] sending...") + this.rc.Do(func() error { + channel := this.rc.Channel("im.ricochet.chat", channels.Outbound) + if channel != nil { + peerchannel, ok := channel.Handler.(*channels.ChatChannel) + if ok { + log.Printf("[alice] sending '%s' to echobot", message) + this.messages[peerchannel.SendMessage(message)] = message + } else { + log.Fatalf("couldn't cast channel:") + } + } else { + log.Fatalf("couldn't create channel") + } + return nil + }) +} + +func (this *alicebot) OpenInbound() { + log.Printf("[alice] inbound connection established") +} + +func (this *alicebot) ChatMessage(messageID uint32, when time.Time, message string) bool { + log.Printf("[alice] got message from echobot: %s", message) + return true +} + +func (this *alicebot) ChatMessageAck(messageID uint32, accepted bool) { + log.Printf("[alice] message \"%s\" ack'd", this.messages[messageID]) +} \ No newline at end of file diff --git a/channels/chatchannel.go b/channels/chatchannel.go index 42c1f24..b89983b 100644 --- a/channels/chatchannel.go +++ b/channels/chatchannel.go @@ -91,7 +91,7 @@ func (cc *ChatChannel) Bidirectional() bool { // RequiresAuthentication - chat channels require hidden service auth func (cc *ChatChannel) RequiresAuthentication() string { - return "im.ricochet.auth.hidden-service" + return "im.ricochet.auth.3dh" } // OpenInbound is the first method called for an inbound channel request. From 4d3f52102f34d165445554087c7ed86eeb64806e Mon Sep 17 00:00:00 2001 From: erinn Date: Sat, 27 Oct 2018 02:17:35 -0700 Subject: [PATCH 2/2] allow retrieving handlers from an aif so we can merge them in cwtch peers --- application/application_factory.go | 16 ++++++++++++++++ application/examples/echobot/main.go | 10 ++++------ connection/handler.go | 2 +- 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/application/application_factory.go b/application/application_factory.go index 1710915..1361e8e 100644 --- a/application/application_factory.go +++ b/application/application_factory.go @@ -27,6 +27,22 @@ func (af *ApplicationInstanceFactory) AddHandler(ctype string, chandler func(*Ap af.handlerMap[ctype] = chandler } +func (af *ApplicationInstanceFactory) GetHandlers() []string { + keys := make([]string, len(af.handlerMap)) + + i := 0 + for k := range af.handlerMap { + keys[i] = k + i++ + } + + return keys +} + +func (af *ApplicationInstanceFactory) GetHandler(ctype string) func(*ApplicationInstance) func() channels.Handler { + return af.handlerMap[ctype] +} + // GetApplicationInstance builds a new application instance using a connection as a base. func (af *ApplicationInstanceFactory) GetApplicationInstance(rc *connection.Connection) *ApplicationInstance { rai := new(ApplicationInstance) diff --git a/application/examples/echobot/main.go b/application/examples/echobot/main.go index d1af675..f1bb4a1 100644 --- a/application/examples/echobot/main.go +++ b/application/examples/echobot/main.go @@ -40,9 +40,7 @@ func (ebi *EchoBotInstance) OpenInbound() { func (ebi *EchoBotInstance) ChatMessage(messageID uint32, when time.Time, message string) bool { log.Printf("message from %v - %v", ebi.rai.RemoteHostname, message) - go ebi.ra.Broadcast(func(rai *application.ApplicationInstance) { - ebi.SendChatMessage(rai, ebi.rai.RemoteHostname+" "+message) - }) + ebi.SendChatMessage(ebi.rai, ebi.rai.RemoteHostname+" "+message) return true } @@ -51,14 +49,14 @@ func (ebi *EchoBotInstance) ChatMessageAck(messageID uint32, accepted bool) { } func (ebi *EchoBotInstance) SendChatMessage(rai *application.ApplicationInstance, message string) { - rai.Connection.Do(func() error { - channel := rai.Connection.Channel("im.ricochet.chat", channels.Outbound) + ebi.rai.Connection.Do(func() error { + channel := ebi.rai.Connection.Channel("im.ricochet.chat", channels.Outbound) if channel != nil { chatchannel, ok := channel.Handler.(*channels.ChatChannel) if ok { chatchannel.SendMessage(message) } - } + } //TODO: else? return nil }) } diff --git a/connection/handler.go b/connection/handler.go index 9a6c42b..f167b48 100644 --- a/connection/handler.go +++ b/connection/handler.go @@ -27,4 +27,4 @@ type Handler interface { OnOpenChannelRequest(ctype string) (channels.Handler, error) GetSupportedChannelTypes() []string -} +} \ No newline at end of file