diff --git a/features/servers/servers_functionality.go b/features/servers/servers_functionality.go index b80a247..6b25c1a 100644 --- a/features/servers/servers_functionality.go +++ b/features/servers/servers_functionality.go @@ -110,7 +110,7 @@ func (sf *ServersFunctionality) Enable() { func (sf *ServersFunctionality) LoadServers(password string) ([]string, error) { servers, err := appServers.LoadServers(password) - // server:1.3/libcwtch-go:1.4 accidentely enabled monitor logging by default. make sure it's turned off + // server:1.3/libcwtch-go:1.4 accidentally enabled monitor logging by default. make sure it's turned off for _, onion := range servers { server := appServers.GetServer(onion) server.SetMonitorLogging(false) diff --git a/go.mod b/go.mod index 4407fe2..8b78b3c 100644 --- a/go.mod +++ b/go.mod @@ -3,12 +3,12 @@ module git.openprivacy.ca/cwtch.im/libcwtch-go go 1.15 require ( - cwtch.im/cwtch v0.14.11 + cwtch.im/cwtch v0.14.17 git.openprivacy.ca/cwtch.im/server v1.4.2 - git.openprivacy.ca/openprivacy/connectivity v1.6.0 + git.openprivacy.ca/openprivacy/connectivity v1.8.1 git.openprivacy.ca/openprivacy/log v1.0.3 github.com/mutecomm/go-sqlcipher/v4 v4.4.2 golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f // indirect golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect golang.org/x/text v0.3.7 // indirect -) +) \ No newline at end of file diff --git a/go.sum b/go.sum index 40a5289..640c61c 100644 --- a/go.sum +++ b/go.sum @@ -17,25 +17,29 @@ cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2k cloud.google.com/go/storage v1.0.0 h1:VV2nUM3wwLLGh9lSABFgZMjInyUbJeaRSE64WuAIQ+4= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cwtch.im/cwtch v0.14.9/go.mod h1:/fLuoYLY/7JHw6RojFojpd245CiOcU24QpWqzh9FRDI= -cwtch.im/cwtch v0.14.10 h1:RA/hehCxeAE+J6YkUuEvS6n8blEAK2ixGnKbq23bN10= -cwtch.im/cwtch v0.14.10/go.mod h1:/fLuoYLY/7JHw6RojFojpd245CiOcU24QpWqzh9FRDI= -cwtch.im/cwtch v0.14.11 h1:nn2XM0sBbUZXKlFl8hFq62gpWjwk7hhVFM53BUF20lU= -cwtch.im/cwtch v0.14.11/go.mod h1:E0Obl/rjrC65guq39SiuUb+p9tZH+ww/7Z8IjQe9Vqo= +cwtch.im/cwtch v0.14.15 h1:WnDxtlKRLasA+ycUtkWy+O74PJxx842csmNIiVg4iKU= +cwtch.im/cwtch v0.14.15/go.mod h1:VH4mDRXe0BuMPQ2NQNn+c1nENeiBzmAqVmMmi48FsoA= +cwtch.im/cwtch v0.14.16 h1:PaODj0jCXR8UI3ro3Aplvou1xVV6w8m+mhwbnnPu8oQ= +cwtch.im/cwtch v0.14.16/go.mod h1:lG9e5RUib+SbX2XsjWtHKJWz9geoIglSAq55LrCm8Io= +cwtch.im/cwtch v0.14.17 h1:C9d4DOq2T+rE3vgKOrlYbxFj14uQiVZbwNN4DIEU/jI= +cwtch.im/cwtch v0.14.17/go.mod h1:lG9e5RUib+SbX2XsjWtHKJWz9geoIglSAq55LrCm8Io= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9 h1:VpgP7xuJadIUuKccphEpTJnWhS2jkQyMt6Y7pJCD7fY= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU= filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= git.openprivacy.ca/cwtch.im/server v1.4.2 h1:ZcRK1XuWvJzNjYdAvAISD8HcEITPwWbvRiIZGkMKu1k= git.openprivacy.ca/cwtch.im/server v1.4.2/go.mod h1:CeE/bThy2UVQ+gx+3ctNt65H9xvELDfcwBS9qJwOsOg= -git.openprivacy.ca/cwtch.im/tapir v0.4.9 h1:LXonlztwvI1F1++0IyomIcDH1/Bxzo+oN8YjGonNvjM= git.openprivacy.ca/cwtch.im/tapir v0.4.9/go.mod h1:p4bHo3DAO8wwimU6JAeZXbfPQ4jnoA2bV+4YvknWTNQ= git.openprivacy.ca/cwtch.im/tapir v0.4.10 h1:oYvqae3UM0EwDH67dxEsculQxJzzkDDv9bCLeAeD2k8= git.openprivacy.ca/cwtch.im/tapir v0.4.10/go.mod h1:utT7lp5PsiYXKBQL/QKKiJQWtziJutZKAO5mwjMUTPE= +git.openprivacy.ca/cwtch.im/tapir v0.5.0 h1:bHVZ0GtMe3nkNVY7PoKOyp6f8HHmksdEvhHgfppV/C8= +git.openprivacy.ca/cwtch.im/tapir v0.5.0/go.mod h1:dvcAGBGbgKLDIOu6uyBryR6Fpq6v7QUDLev+w7xOh/Y= git.openprivacy.ca/openprivacy/bine v0.0.4 h1:CO7EkGyz+jegZ4ap8g5NWRuDHA/56KKvGySR6OBPW+c= git.openprivacy.ca/openprivacy/bine v0.0.4/go.mod h1:13ZqhKyqakDsN/ZkQkIGNULsmLyqtXc46XBcnuXm/mU= git.openprivacy.ca/openprivacy/connectivity v1.5.0/go.mod h1:UjQiGBnWbotmBzIw59B8H6efwDadjkKzm3RPT1UaIRw= -git.openprivacy.ca/openprivacy/connectivity v1.6.0 h1:j44Kya3GBH4BDGh0f5JD/eNAb77XiQreIZtzcY8Gn28= git.openprivacy.ca/openprivacy/connectivity v1.6.0/go.mod h1:UjQiGBnWbotmBzIw59B8H6efwDadjkKzm3RPT1UaIRw= +git.openprivacy.ca/openprivacy/connectivity v1.8.1 h1:OjWy+JTAvlrstY8PnGPBp7Ho04JaKHaQ+YdoLwSdaCo= +git.openprivacy.ca/openprivacy/connectivity v1.8.1/go.mod h1:UjQiGBnWbotmBzIw59B8H6efwDadjkKzm3RPT1UaIRw= git.openprivacy.ca/openprivacy/log v1.0.2/go.mod h1:gGYK8xHtndRLDymFtmjkG26GaMQNgyhioNS82m812Iw= git.openprivacy.ca/openprivacy/log v1.0.3 h1:E/PMm4LY+Q9s3aDpfySfEDq/vYQontlvNj/scrPaga0= git.openprivacy.ca/openprivacy/log v1.0.3/go.mod h1:gGYK8xHtndRLDymFtmjkG26GaMQNgyhioNS82m812Iw= diff --git a/lib.go b/lib.go index 9c7d9b3..080e464 100644 --- a/lib.go +++ b/lib.go @@ -10,6 +10,8 @@ import ( "crypto/rand" "encoding/json" "fmt" + "io/ioutil" + path "path/filepath" "strconv" constants2 "cwtch.im/cwtch/model/constants" @@ -41,7 +43,6 @@ import ( "encoding/base64" mrand "math/rand" "os" - "path/filepath" "time" "git.openprivacy.ca/openprivacy/connectivity/tor" @@ -140,7 +141,7 @@ func _startCwtch(appDir string, torPath string) { if appDir == "~" { appDir = homeDir } else if strings.HasPrefix(appDir, "~/") { - appDir = filepath.Join(homeDir, appDir[2:]) + appDir = path.Join(homeDir, appDir[2:]) } // Ensure that the application directory exists...and then initialize settings.. @@ -159,7 +160,7 @@ func _startCwtch(appDir string, torPath string) { log.Infof("Loading Cwtch Directory %v and tor path: %v", appDir, torPath) log.Infof("making directory %v", appDir) - err = os.MkdirAll(filepath.Join(appDir, "tor"), 0700) + err = os.MkdirAll(path.Join(appDir, "tor"), 0700) if err != nil { log.Errorf("error creating tor data directory: %v. Aborting app start up", err) @@ -195,6 +196,8 @@ func _startCwtch(appDir string, torPath string) { event.FileDownloaded, } + // Settings may have changed... + settings = utils.ReadGlobalSettings() settingsJson, _ := json.Marshal(settings) application.LoadProfiles(constants.DefactoPasswordForUnencryptedProfiles) @@ -231,7 +234,7 @@ func buildACN(settings utils.GlobalSettings, torPath string, appDir string) conn } log.Infof("making directory %v", appDir) - err = os.MkdirAll(filepath.Join(appDir, "tor"), 0700) + err = os.MkdirAll(path.Join(appDir, "tor"), 0700) if err != nil { log.Errorf("error creating tor data directory: %v. Aborting app start up", err) @@ -256,7 +259,7 @@ func buildACN(settings utils.GlobalSettings, torPath string, appDir string) conn utils.WriteGlobalSettings(settings) } - err = torrc.Build(filepath.Join(appDir, "tor", "torrc")) + err = torrc.Build(path.Join(appDir, "tor", "torrc")) if err != nil { log.Errorf("error constructing torrc: %v", err) @@ -264,7 +267,32 @@ func buildACN(settings utils.GlobalSettings, torPath string, appDir string) conn return &connectivity.ErrorACN{} } - acn, err := tor.NewTorACNWithAuth(appDir, torPath, controlPort, tor.HashedPasswordAuthenticator{Password: base64.StdEncoding.EncodeToString(key)}) + dataDir := settings.TorCacheDir + if !settings.UseTorCache { + + // purge data dir directories if we are not using them for a cache + torDir := path.Join(appDir, "tor") + files, err := path.Glob(path.Join(torDir, "data-dir-*")) + if err != nil { + log.Errorf("could not construct filesystem glob: %v", err) + } + for _, f := range files { + if err := os.RemoveAll(f); err != nil { + log.Errorf("could not remove data-dir: %v", err) + } + } + + if dataDir, err = ioutil.TempDir(torDir, "data-dir-"); err != nil { + eventHandler.Push(event.NewEventList(utils.CwtchStartError, event.Error, fmt.Sprintf("Error connecting to Tor: %v", err))) + return &connectivity.ErrorACN{} + } + } + + // Persist Current Data Dir as Tor Cache... + settings.TorCacheDir = dataDir + utils.WriteGlobalSettings(settings) + + acn, err := tor.NewTorACNWithAuth(appDir, torPath, dataDir, controlPort, tor.HashedPasswordAuthenticator{Password: base64.StdEncoding.EncodeToString(key)}) if err != nil { log.Errorf("Error connecting to Tor replacing with ErrorACN: %v\n", err) eventHandler.Push(event.NewEventList(utils.CwtchStartError, event.Error, fmt.Sprintf("Error connecting to Tor: %v", err))) @@ -300,7 +328,7 @@ func ReconnectCwtchForeground() { profile := application.GetPeer(profileOnion) conversations, _ := profile.FetchConversations() for _, conversation := range conversations { - if (conversation.IsGroup() && groupHandler != nil) || conversation.IsServer() == false { + if (conversation.IsGroup() && groupHandler != nil) || !conversation.IsServer() { totalMessages, _ := profile.GetChannelMessageCount(conversation.ID, 0) eventHandler.Push(event.NewEvent(event.MessageCounterResync, map[event.Field]string{ event.Identity: profileOnion, @@ -548,6 +576,8 @@ func c_GetMessage(profile_ptr *C.char, profile_len C.int, conversation_id C.int, type EnhancedMessage struct { model.Message ID int // the actual ID of the message in the database (not the row number) + LocalIndex int // local index in the DB (row #). Can be empty (most calls supply it) but lookup by hash will fill it + ContentHash string ContactImage string Attributes map[string]string } @@ -574,6 +604,7 @@ func GetMessage(profileOnion string, conversationID int, messageIndex int) strin message.ID = messages[0].ID message.Attributes = messages[0].Attr message.ContactImage = utils.RandomProfileImage(message.PeerID) + message.ContentHash = model.CalculateContentHash(messages[0].Attr[constants2.AttrAuthor], messages[0].Body) } } bytes, _ := json.Marshal(message) @@ -587,7 +618,7 @@ func c_GetMessageByID(profile_ptr *C.char, profile_len C.int, conversation_id C. return C.CString(GetMessageByID(profile, int(conversation_id), int(message_index))) } -func GetMessageByID(profileOnion string, conversationID int, messageIndex int) string { +func GetMessageByID(profileOnion string, conversationID int, messageID int) string { var message EnhancedMessage // There is an edge case that can happen on Android when the app is shutdown while fetching messages... // The worker threads that are spawned can become activated again when the app is opened attempt to finish their job... @@ -596,7 +627,7 @@ func GetMessageByID(profileOnion string, conversationID int, messageIndex int) s // these requests complete almost immediately v.s. being stalled for seconds to minutes on large groups. if application != nil { profile := application.GetPeer(profileOnion) - dbmessage, attr, err := profile.GetChannelMessage(conversationID, 0, messageIndex) + dbmessage, attr, err := profile.GetChannelMessage(conversationID, 0, messageID) if err == nil { time, _ := time.Parse(time.RFC3339Nano, attr[constants2.AttrSentTimestamp]) message.Message = model.Message{ @@ -606,9 +637,10 @@ func GetMessageByID(profileOnion string, conversationID int, messageIndex int) s PeerID: attr[constants2.AttrAuthor], Timestamp: time, } - message.ID = messageIndex + message.ID = messageID message.Attributes = attr message.ContactImage = utils.RandomProfileImage(message.PeerID) + message.ContentHash = model.CalculateContentHash(attr[constants2.AttrAuthor], dbmessage) } } bytes, _ := json.Marshal(message) @@ -624,7 +656,7 @@ func c_GetMessagesByContentHash(profile_ptr *C.char, profile_len C.int, conversa } func GetMessagesByContentHash(profileOnion string, handle int, contentHash string) string { - var indexedMessages []model.LocallyIndexedMessage + var message EnhancedMessage if application != nil { profile := application.GetPeer(profileOnion) offset, err := profile.GetChannelMessageByContentHash(handle, 0, contentHash) @@ -632,21 +664,24 @@ func GetMessagesByContentHash(profileOnion string, handle int, contentHash strin messages, err := profile.GetMostRecentMessages(handle, 0, offset, 1) if err == nil { time, _ := time.Parse(time.RFC3339Nano, messages[0].Attr[constants2.AttrSentTimestamp]) - msg := model.Message{ + message.Message = model.Message{ Message: messages[0].Body, Acknowledged: messages[0].Attr[constants2.AttrAck] == constants2.True, Error: messages[0].Attr[constants2.AttrErr], PeerID: messages[0].Attr[constants2.AttrAuthor], Timestamp: time, } - // TODO this is mostly unused at this point, consider cleaning is up in 1.6 - indexedMessages = append(indexedMessages, model.LocallyIndexedMessage{LocalIndex: offset, Message: msg}) + message.ID = messages[0].ID + message.Attributes = messages[0].Attr + message.ContactImage = utils.RandomProfileImage(message.PeerID) + message.LocalIndex = offset + message.ContentHash = contentHash } else { log.Errorf("error fetching local index {} ", err) } } } - bytes, _ := json.Marshal(indexedMessages) + bytes, _ := json.Marshal(message) return string(bytes) } @@ -776,7 +811,15 @@ func c_ResetTor() { func ResetTor() { log.Infof("Replacing ACN with new Tor...") - globalACN.ReplaceACN(buildACN(*utils.ReadGlobalSettings(), globalTorPath, globalAppDir)) + settings := utils.ReadGlobalSettings() + + globalACN.Close() // we need to close first if dateDir is the same, otherwise buildACN can't launch tor. + globalACN.ReplaceACN(buildACN(*settings, globalTorPath, globalAppDir)) + + // We need to update settings on reset as buildACN can alter settings, otherwise the next reset will be broken... + settings = utils.ReadGlobalSettings() + settingsJson, _ := json.Marshal(settings) + application.GetPrimaryBus().Publish(event.NewEvent(utils.UpdateGlobalSettings, map[event.Field]string{event.Data: string(settingsJson)})) log.Infof("Restarted") } diff --git a/utils/eventHandler.go b/utils/eventHandler.go index e69ac2d..c041bbe 100644 --- a/utils/eventHandler.go +++ b/utils/eventHandler.go @@ -437,7 +437,7 @@ func (eh *EventHandler) startHandlingPeer(onion string) { q := event.NewQueue() // eventBus.Subscribe(event.NetworkStatus, q) - + eventBus.Subscribe(event.ACNInfo, q) eventBus.Subscribe(event.NewMessageFromPeer, q) eventBus.Subscribe(event.UpdatedProfileAttribute, q) eventBus.Subscribe(event.PeerAcknowledgement, q) diff --git a/utils/settings.go b/utils/settings.go index 4f15a07..5acfee1 100644 --- a/utils/settings.go +++ b/utils/settings.go @@ -1,6 +1,7 @@ package utils import ( + path "path/filepath" "sync" "cwtch.im/cwtch/event" @@ -9,7 +10,6 @@ import ( "encoding/json" "io/ioutil" "os" - "path" "git.openprivacy.ca/openprivacy/log" ) @@ -46,6 +46,8 @@ type GlobalSettings struct { UseExternalTor bool CustomSocksPort int CustomControlPort int + UseTorCache bool + TorCacheDir string } var DefaultGlobalSettings = GlobalSettings{ @@ -66,6 +68,8 @@ var DefaultGlobalSettings = GlobalSettings{ UseCustomTorrc: false, CustomSocksPort: -1, CustomControlPort: -1, + UseTorCache: false, + TorCacheDir: "", } func InitGlobalSettingsFile(directory string, password string) error {