//package cwtch package main import "C" import ( "crypto/rand" "cwtch.im/cwtch/app" "cwtch.im/cwtch/event" "cwtch.im/cwtch/peer" "encoding/json" "fmt" "encoding/base64" "git.openprivacy.ca/openprivacy/connectivity/tor" "git.openprivacy.ca/openprivacy/log" mrand "math/rand" "os" "path" "path/filepath" "time" ) var application app.Application var appBusQueue event.Queue var acnQueue event.Queue var contactEventsQueue event.Queue //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) tor := C.GoStringN(tor_c, torLen) StartCwtch(dir, tor) } func StartCwtch(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) 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, 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 func c_ACNEvents() *C.char { return C.CString(ACNEvents()) } func ACNEvents() string { select { case myevent := <- acnQueue.OutChan(): return fmt.Sprintf("%v", myevent) default: return "" } } //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) } 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 { 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) } type Contact struct { Name string `json:"name"` Onion string `json:"onion"` Status string `json:"status"` } //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))) } func GetContacts(onion string)string { log.Infof("Get Contacts for %v", onion) mypeer := application.GetPeer(onion) contactEventsQueue = event.NewQueue() application.GetEventBus(onion).Subscribe(event.PeerStateChange, contactEventsQueue) var contacts []Contact for _,contact := range mypeer.GetContacts() { contactInfo := mypeer.GetContact(contact) log.Infof("contactInfo %v", contactInfo) contacts = append(contacts, Contact{Name: contactInfo.Name, Onion: contactInfo.Onion, Status: contactInfo.State}) } bytes,_ := json.Marshal(contacts) 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 { 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 "" } //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()) } func ContactEvents() string { select { case myevent := <- contactEventsQueue.OutChan(): return fmt.Sprintf("%v", myevent) default: return "" } } //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) 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 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))) } // 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) log.Infof("GetMessage(%s, %s, %d) = %s", profile, handle, message_index, string(bytes)) 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() {}