From b70da91e5cccd6c02e6a6ed5e59b92ce341c26b0 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Tue, 12 Jan 2021 21:46:33 -0800 Subject: [PATCH 1/5] make c_ function wrappers so can work with gomobile and ffi. change Start to take tor path as well --- .gitignore | 1 + lib.go | 181 ++++++++++++++++++++++++++++++----------------------- 2 files changed, 102 insertions(+), 80 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..485dee6 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea diff --git a/lib.go b/lib.go index d714b6a..ba12705 100644 --- a/lib.go +++ b/lib.go @@ -1,5 +1,5 @@ -//package cwtch -package main +package cwtch +//package main import "C" import ( @@ -24,90 +24,96 @@ var application app.Application var acnQueue event.Queue var contactEventsQueue event.Queue -//export HelloWorld -func HelloWorld(a C.int, b C.int) C.int { - return a+b -} - -//export StartCwtch -func StartCwtch(dir_c *C.char, len C.int) { +//export c_StartCwtch +func c_StartCwtch(dir_c *C.char, len C.int, tor_c *C.char, torLen C.int) { dir := C.GoStringN(dir_c, len) - log.SetLevel(log.LevelDebug) - log.Infof("Loading Cwtch Directory %v", dir) - - mrand.Seed(int64(time.Now().Nanosecond())) - port := mrand.Intn(1000) + 9600 - controlPort := port + 1 - - // generate a random password (actually random, stored in memory, for the control port) - key := make([]byte, 64) - _, err := rand.Read(key) - if err != nil { - panic(err) - } - - log.Infof("making directory %v", dir) - os.MkdirAll(path.Join(dir, "/.tor","tor"),0700) - tor.NewTorrc().WithSocksPort(port).WithOnionTrafficOnly().WithControlPort(controlPort).WithHashedPassword(base64.StdEncoding.EncodeToString(key)).Build(filepath.Join(dir, ".tor", "tor", "torrc")) - acn, err := tor.NewTorACNWithAuth(path.Join(dir, "/.tor"), "", controlPort, tor.HashedPasswordAuthenticator{base64.StdEncoding.EncodeToString(key)}) - if err != nil { - log.Errorf("\nError connecting to Tor: %v\n", err) - } - //acn.WaitTillBootstrapped() - - - newApp := app.NewApp(acn, dir) - id := mrand.Int31() - acnQueue = event.NewQueue() - newApp.GetPrimaryBus().Subscribe(event.ACNStatus, acnQueue) - peer.DefaultEventsToHandle = []event.Type{ - event.EncryptedGroupMessage, - event.NewMessageFromPeer, - event.PeerAcknowledgement, - event.NewGroupInvite, - event.PeerError, - event.SendMessageToGroupError, - event.NewGetValMessageFromPeer, - event.PeerStateChange, - } - newApp.LoadProfiles("be gay do crime") - newApp.LaunchPeers() - application = newApp - log.Infof("Providing Handle %v", id) + tor := C.GoStringN(tor_c, torLen) + StartCwtch(dir, tor) } -//export ACNEvents -func ACNEvents() *C.char { +func StartCwtch(appDir string, torPath string) { + //go func (appDir string, torPath string) { + log.SetLevel(log.LevelDebug) + + log.Infof("Loading Cwtch Directory %v and tor path: %v", appDir, torPath) + + mrand.Seed(int64(time.Now().Nanosecond())) + port := mrand.Intn(1000) + 9600 + controlPort := port + 1 + + // generate a random password (actually random, stored in memory, for the control port) + key := make([]byte, 64) + _, err := rand.Read(key) + if err != nil { + panic(err) + } + + log.Infof("making directory %v", appDir) + os.MkdirAll(path.Join(appDir, "/.tor", "tor"), 0700) + tor.NewTorrc().WithSocksPort(port).WithOnionTrafficOnly().WithControlPort(controlPort).WithHashedPassword(base64.StdEncoding.EncodeToString(key)).Build(filepath.Join(appDir, ".tor", "tor", "torrc")) + acn, err := tor.NewTorACNWithAuth(path.Join(appDir, "/.tor"), torPath, controlPort, tor.HashedPasswordAuthenticator{base64.StdEncoding.EncodeToString(key)}) + if err != nil { + log.Errorf("\nError connecting to Tor: %v\n", err) + } + //acn.WaitTillBootstrapped() + + newApp := app.NewApp(acn, appDir) + acnQueue = event.NewQueue() + newApp.GetPrimaryBus().Subscribe(event.ACNStatus, acnQueue) + peer.DefaultEventsToHandle = []event.Type{ + event.EncryptedGroupMessage, + event.NewMessageFromPeer, + event.PeerAcknowledgement, + event.NewGroupInvite, + event.PeerError, + event.SendMessageToGroupError, + event.NewGetValMessageFromPeer, + event.PeerStateChange, + } + newApp.LoadProfiles("be gay do crime") + newApp.LaunchPeers() + application = newApp + //}(appDir, torPath) +} + +//export c_ACNEvents +func c_ACNEvents() *C.char { + return C.CString(ACNEvents()) +} + +func ACNEvents() string { select { case myevent := <- acnQueue.OutChan(): - return C.CString(fmt.Sprintf("%v", myevent)) + return fmt.Sprintf("%v", myevent) default: - return C.CString("") + return "" } } -//export NextEvent -func NextEvent() { - +//export c_GetProfiles +func c_GetProfiles() *C.char { + return C.CString(GetProfiles()) } -//export GetProfiles -func GetProfiles() *C.char { +func GetProfiles() string { profiles := application.ListPeers() jsonBytes,_ := json.Marshal(profiles) - return C.CString(string(jsonBytes)) + return string(jsonBytes) } + type Contact struct { Name string `json:"name"` Onion string `json:"onion"` Status string `json:"status"` } -//export GetContacts -func GetContacts(onion_ptr *C.char, onion_len C.int) *C.char { +//export c_GetContacts +func c_GetContacts(onion_ptr *C.char, onion_len C.int) *C.char { + return C.CString(GetContacts(C.GoStringN(onion_ptr, onion_len))) +} - onion := C.GoStringN(onion_ptr, onion_len) +func GetContacts(onion string)string { log.Infof("Get Contacts for %v", onion) mypeer := application.GetPeer(onion) @@ -122,48 +128,63 @@ func GetContacts(onion_ptr *C.char, onion_len C.int) *C.char { } bytes,_ := json.Marshal(contacts) - return C.CString(string(bytes)) + return string(bytes) } -//export SelectProfile -func SelectProfile(onion_ptr *C.char, onion_len C.int) *C.char { - onion := C.GoStringN(onion_ptr, onion_len) +//export c_SelectProfile +func c_SelectProfile(onion_ptr *C.char, onion_len C.int) *C.char { + return C.CString(SelectProfile(C.GoStringN(onion_ptr, onion_len))) +} + +func SelectProfile(onion string) string { log.Infof("Select Profile: %v", onion) contactEventsQueue = event.NewQueue() application.GetEventBus(onion).Subscribe(event.PeerStateChange, contactEventsQueue) - return C.CString("") + return "" } -//export ContactEvents -func ContactEvents() *C.char { +//export c_ContactEvents +func c_ContactEvents() *C.char { + return C.CString(ContactEvents()) +} + +func ContactEvents() string { select { case myevent := <- contactEventsQueue.OutChan(): - return C.CString(fmt.Sprintf("%v", myevent)) + return fmt.Sprintf("%v", myevent) default: - return C.CString("") + return "" } } -//export NumMessages -func NumMessages(profile_ptr *C.char, profile_len C.int, handle_ptr *C.char, handle_len C.int) (n C.int) { +//export c_NumMessages +func c_NumMessages(profile_ptr *C.char, profile_len C.int, handle_ptr *C.char, handle_len C.int) (n C.int) { profile := C.GoStringN(profile_ptr, profile_len) handle := C.GoStringN(handle_ptr, handle_len) - n = C.int(len(application.GetPeer(profile).GetContact(handle).Timeline.Messages)) + return C.int(NumMessages(profile, handle)) +} + +func NumMessages(profile, handle string) (n int) { + n = len(application.GetPeer(profile).GetContact(handle).Timeline.Messages) log.Infof("NumMessagse(%s, %s) = %d", profile, handle, n) return } -//export GetMessage -func GetMessage(profile_ptr *C.char, profile_len C.int, handle_ptr *C.char, handle_len C.int, message_index C.int) *C.char { +//export c_GetMessage +func c_GetMessage(profile_ptr *C.char, profile_len C.int, handle_ptr *C.char, handle_len C.int, message_index C.int) *C.char { profile := C.GoStringN(profile_ptr, profile_len) handle := C.GoStringN(handle_ptr, handle_len) + return C.CString(GetMessage(profile, handle, int(message_index))) +} + +func GetMessage(profile, handle string, message_index int) string { message := application.GetPeer(profile).GetContact(handle).Timeline.Messages[message_index] bytes,_ := json.Marshal(message) log.Infof("GetMessage(%s, %s, %d) = %s", profile, handle, message_index, string(bytes)) - return C.CString(string(bytes)) + return string(bytes) } // Leave as is, needed by ffi -func main() {} \ No newline at end of file +//func main() {} \ No newline at end of file From 120dc5f468d1b6fb9f7450beae1dd8dbc7ae00c5 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Thu, 14 Jan 2021 15:34:08 -0800 Subject: [PATCH 2/5] add GetMessages --- .gitignore | 4 +++ README.md | 12 ++++++-- lib.go | 87 +++++++++++++++++++++++++++++++----------------------- 3 files changed, 64 insertions(+), 39 deletions(-) diff --git a/.gitignore b/.gitignore index 485dee6..c24322b 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,5 @@ .idea +cwtch-sources.jar +cwtch.aar +libCwtch.h +libCwtch.so diff --git a/README.md b/README.md index 4bb7050..2a98146 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,14 @@ # Build Instructions... - go build -buildmode c-shared -o libCwtch.so + make linux + make android # Using -LD_LIBRARY_PATH set to point to libCwtch.so +## Linux Desktop: + + - `LD_LIBRARY_PATH` set to point to `libCwtch.so` + - or drop a symlink into `/usr/lib` + +## Android + +- copy `cwtch.aar` into `flutter_app/android/cwtch` diff --git a/lib.go b/lib.go index ba12705..841be96 100644 --- a/lib.go +++ b/lib.go @@ -32,48 +32,47 @@ func c_StartCwtch(dir_c *C.char, len C.int, tor_c *C.char, torLen C.int) { } func StartCwtch(appDir string, torPath string) { - //go func (appDir string, torPath string) { - log.SetLevel(log.LevelDebug) + log.SetLevel(log.LevelDebug) - log.Infof("Loading Cwtch Directory %v and tor path: %v", appDir, torPath) + log.Infof("Loading Cwtch Directory %v and tor path: %v", appDir, torPath) - mrand.Seed(int64(time.Now().Nanosecond())) - port := mrand.Intn(1000) + 9600 - controlPort := port + 1 + mrand.Seed(int64(time.Now().Nanosecond())) + port := mrand.Intn(1000) + 9600 + controlPort := port + 1 - // generate a random password (actually random, stored in memory, for the control port) - key := make([]byte, 64) - _, err := rand.Read(key) - if err != nil { - panic(err) - } + // generate a random password (actually random, stored in memory, for the control port) + key := make([]byte, 64) + _, err := rand.Read(key) + if err != nil { + panic(err) + } - log.Infof("making directory %v", appDir) - os.MkdirAll(path.Join(appDir, "/.tor", "tor"), 0700) - tor.NewTorrc().WithSocksPort(port).WithOnionTrafficOnly().WithControlPort(controlPort).WithHashedPassword(base64.StdEncoding.EncodeToString(key)).Build(filepath.Join(appDir, ".tor", "tor", "torrc")) - acn, err := tor.NewTorACNWithAuth(path.Join(appDir, "/.tor"), torPath, controlPort, tor.HashedPasswordAuthenticator{base64.StdEncoding.EncodeToString(key)}) - if err != nil { - log.Errorf("\nError connecting to Tor: %v\n", err) - } - //acn.WaitTillBootstrapped() + log.Infof("making directory %v", appDir) + os.MkdirAll(path.Join(appDir, "/.tor", "tor"), 0700) + tor.NewTorrc().WithSocksPort(port).WithOnionTrafficOnly().WithControlPort(controlPort).WithHashedPassword(base64.StdEncoding.EncodeToString(key)).Build(filepath.Join(appDir, ".tor", "tor", "torrc")) + acn, err := tor.NewTorACNWithAuth(path.Join(appDir, "/.tor"), torPath, controlPort, tor.HashedPasswordAuthenticator{base64.StdEncoding.EncodeToString(key)}) + if err != nil { + log.Errorf("\nError connecting to Tor: %v\n", err) + } + //acn.WaitTillBootstrapped() - newApp := app.NewApp(acn, appDir) - acnQueue = event.NewQueue() - newApp.GetPrimaryBus().Subscribe(event.ACNStatus, acnQueue) - peer.DefaultEventsToHandle = []event.Type{ - event.EncryptedGroupMessage, - event.NewMessageFromPeer, - event.PeerAcknowledgement, - event.NewGroupInvite, - event.PeerError, - event.SendMessageToGroupError, - event.NewGetValMessageFromPeer, - event.PeerStateChange, - } - newApp.LoadProfiles("be gay do crime") - newApp.LaunchPeers() - application = newApp - //}(appDir, torPath) + newApp := app.NewApp(acn, appDir) + acnQueue = event.NewQueue() + newApp.GetPrimaryBus().Subscribe(event.ACNStatus, acnQueue) + peer.DefaultEventsToHandle = []event.Type{ + event.EncryptedGroupMessage, + event.NewMessageFromPeer, + event.PeerAcknowledgement, + event.NewGroupInvite, + event.PeerError, + event.SendMessageToGroupError, + event.NewGetValMessageFromPeer, + event.PeerStateChange, + } + newApp.LoadProfiles("be gay do crime") + newApp.LaunchPeers() + application = newApp + log.Infof("libcwtch-go application SET\n") } //export c_ACNEvents @@ -179,6 +178,7 @@ func c_GetMessage(profile_ptr *C.char, profile_len C.int, handle_ptr *C.char, ha return C.CString(GetMessage(profile, handle, int(message_index))) } +// Deprecate - 2021.01.14 - not used func GetMessage(profile, handle string, message_index int) string { message := application.GetPeer(profile).GetContact(handle).Timeline.Messages[message_index] bytes,_ := json.Marshal(message) @@ -186,5 +186,18 @@ func GetMessage(profile, handle string, message_index int) string { return string(bytes) } +//export c_GetMessages +func c_GetMessages(profile_ptr *C.char, profile_len C.int, handle_ptr *C.char, handle_len C.int, start C.int, end C.int) *C.char { + profile := C.GoStringN(profile_ptr, profile_len) + handle := C.GoStringN(handle_ptr, handle_len) + return C.CString(GetMessages(profile, handle, int(start), int(end))) +} + +func GetMessages(profile, handle string, start, end int) string { + messages := application.GetPeer(profile).GetContact(handle).Timeline.Messages[start:end] + bytes,_ := json.Marshal(messages) + return string(bytes) +} + // Leave as is, needed by ffi //func main() {} \ No newline at end of file From 9c7a22d47214fef5bf37d1de04f2b42526b51a71 Mon Sep 17 00:00:00 2001 From: Dan Ballard Date: Wed, 20 Jan 2021 12:05:37 -0800 Subject: [PATCH 3/5] getAppBusEvents for gomobile --- lib.go | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/lib.go b/lib.go index 841be96..77b546e 100644 --- a/lib.go +++ b/lib.go @@ -21,6 +21,7 @@ import ( ) var application app.Application +var appBusQueue event.Queue var acnQueue event.Queue var contactEventsQueue event.Queue @@ -59,6 +60,16 @@ func StartCwtch(appDir string, torPath string) { newApp := app.NewApp(acn, appDir) acnQueue = event.NewQueue() newApp.GetPrimaryBus().Subscribe(event.ACNStatus, acnQueue) + + appBusQueue = event.NewQueue() + newApp.GetPrimaryBus().Subscribe(event.NewPeer, appBusQueue) + newApp.GetPrimaryBus().Subscribe(event.PeerError, appBusQueue) + newApp.GetPrimaryBus().Subscribe(event.AppError, appBusQueue) + newApp.GetPrimaryBus().Subscribe(event.ACNStatus, appBusQueue) + newApp.GetPrimaryBus().Subscribe(event.ReloadDone, appBusQueue) + newApp.GetPrimaryBus().Subscribe(event.ACNVersion, appBusQueue) + + // Lol this wasn't an intended use peer.DefaultEventsToHandle = []event.Type{ event.EncryptedGroupMessage, event.NewMessageFromPeer, @@ -89,6 +100,12 @@ func ACNEvents() string { } } +// GetAppBusEvent blocks until an event +func GetAppBusEvent() string { + event := appBusQueue.Next() + return fmt.Sprintf("%v", event) +} + //export c_GetProfiles func c_GetProfiles() *C.char { return C.CString(GetProfiles()) From 240c4d36e02987e0ea7893326517d0c23922e5c5 Mon Sep 17 00:00:00 2001 From: erinn Date: Fri, 22 Jan 2021 00:00:03 -0800 Subject: [PATCH 4/5] merging dan gomobile with erinn ui --- lib.go | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/lib.go b/lib.go index 77b546e..751d0cf 100644 --- a/lib.go +++ b/lib.go @@ -106,13 +106,29 @@ func GetAppBusEvent() string { return fmt.Sprintf("%v", event) } +type Profile struct { + Name string `json:"name"` + Onion string `json:"onion"` + ImagePath string `json:"imagePath"` +} + //export c_GetProfiles func c_GetProfiles() *C.char { return C.CString(GetProfiles()) } func GetProfiles() string { - profiles := application.ListPeers() + peerList := application.ListPeers() + profiles := make([]Profile, len(peerList)) + i := 0 + for onion, name := range peerList { + profiles[i] = Profile{ + Name: name, + Onion: onion, + ImagePath: "", + } + i += 1 + } jsonBytes,_ := json.Marshal(profiles) return string(jsonBytes) } @@ -147,7 +163,14 @@ func GetContacts(onion string)string { return string(bytes) } +//export c_CreateProfile +func c_CreateProfile(nick_ptr *C.char, nick_len C.int, pass_ptr *C.char, pass_len C.int) { + CreateProfile(C.GoStringN(nick_ptr, nick_len), C.GoStringN(pass_ptr, pass_len)) +} +func CreateProfile(nick, pass string) { + application.CreatePeer(nick, pass) +} //export c_SelectProfile func c_SelectProfile(onion_ptr *C.char, onion_len C.int) *C.char { From 92f74b2dc67d7c4123f9b165327c637567a35f0f Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Tue, 26 Jan 2021 14:38:06 -0800 Subject: [PATCH 5/5] Unlock Profiles --- lib.go | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/lib.go b/lib.go index 751d0cf..a9b71db 100644 --- a/lib.go +++ b/lib.go @@ -1,5 +1,5 @@ -package cwtch -//package main +//package cwtch +package main import "C" import ( @@ -100,8 +100,20 @@ func ACNEvents() string { } } +//export c_AppBusEvent +func c_AppBusEvent() *C.char { + return C.CString(GetAppBusEvent()) +} + + // GetAppBusEvent blocks until an event func GetAppBusEvent() string { + select { + case myevent := <- acnQueue.OutChan(): + return fmt.Sprintf("%v", myevent) + default: + return "" + } event := appBusQueue.Next() return fmt.Sprintf("%v", event) } @@ -184,6 +196,15 @@ func SelectProfile(onion string) string { return "" } +//export c_LoadProfiles +func c_LoadProfiles(passwordPtr *C.char, passwordLen C.int) { + LoadProfiles(C.GoStringN(passwordPtr, passwordLen)) +} + +func LoadProfiles(pass string) { + application.LoadProfiles(pass) +} + //export c_ContactEvents func c_ContactEvents() *C.char { return C.CString(ContactEvents()) @@ -240,4 +261,4 @@ func GetMessages(profile, handle string, start, end int) string { } // Leave as is, needed by ffi -//func main() {} \ No newline at end of file +func main() {} \ No newline at end of file