diff --git a/.drone.yml b/.drone.yml index b8ffb67..31d3246 100644 --- a/.drone.yml +++ b/.drone.yml @@ -5,7 +5,7 @@ name: linux-android-windows-test steps: - name: fetch - image: golang + image: golang:1.17.5 volumes: - name: deps path: /go @@ -23,7 +23,7 @@ steps: - echo `date +%G-%m-%d-%H-%M` > BUILDDATE - name: quality - image: golang + image: golang:1.17.5 volumes: - name: deps path: /go @@ -33,7 +33,7 @@ steps: #Todo: fix all the lint errors and add `-set_exit_status` above to enforce linting - name: build-linux - image: golang + image: golang:1.17.5 volumes: - name: deps path: /go @@ -62,6 +62,7 @@ steps: - name: deploy-buildfiles image: kroniak/ssh-client + pull: if-not-exists environment: BUILDFILES_KEY: from_secret: buildfiles_key @@ -86,6 +87,7 @@ steps: - name: gitea-release image: plugins/gitea-release + pull: if-not-exists when: event: tag settings: @@ -104,6 +106,7 @@ steps: - name: notify-email image: drillster/drone-email + pull: if-not-exists settings: host: build.openprivacy.ca port: 25 @@ -114,6 +117,7 @@ steps: - name: notify-gogs image: openpriv/drone-gogs + pull: if-not-exists when: event: pull_request status: [ success, changed, failure ] diff --git a/features/servers/servers_functionality.go b/features/servers/servers_functionality.go index 41a8fce..b80a247 100644 --- a/features/servers/servers_functionality.go +++ b/features/servers/servers_functionality.go @@ -144,6 +144,11 @@ func (sf *ServersFunctionality) DeleteServer(onion string, currentPassword strin func (sf *ServersFunctionality) LaunchServer(onion string) { appServers.LaunchServer(onion) + server := appServers.GetServer(onion) + if server != nil { + newStats := server.GetStatistics() + publishFn(event.NewEventList(ServerStatsUpdate, event.Identity, onion, TotalMessages, strconv.Itoa(newStats.TotalMessages), Connections, strconv.Itoa(newStats.TotalConnections))) + } } func (sf *ServersFunctionality) StopServer(onion string) { @@ -195,10 +200,12 @@ func cacheForwardServerMetricUpdates() { serverList := appServers.ListServers() for _, serverOnion := range serverList { server := appServers.GetServer(serverOnion) - newStats := server.GetStatistics() - if stats, ok := cache[serverOnion]; !ok || stats.TotalConnections != newStats.TotalConnections || stats.TotalMessages != newStats.TotalMessages { - cache[serverOnion] = newStats - publishFn(event.NewEventList(ServerStatsUpdate, event.Identity, serverOnion, TotalMessages, strconv.Itoa(newStats.TotalMessages), Connections, strconv.Itoa(newStats.TotalConnections))) + if running, err := server.CheckStatus(); running && err == nil { + newStats := server.GetStatistics() + if stats, ok := cache[serverOnion]; !ok || stats.TotalConnections != newStats.TotalConnections || stats.TotalMessages != newStats.TotalMessages { + cache[serverOnion] = newStats + publishFn(event.NewEventList(ServerStatsUpdate, event.Identity, serverOnion, TotalMessages, strconv.Itoa(newStats.TotalMessages), Connections, strconv.Itoa(newStats.TotalConnections))) + } } } case <-killStatsUpdate: diff --git a/go.mod b/go.mod index d4052a4..bf6dce7 100644 --- a/go.mod +++ b/go.mod @@ -3,10 +3,13 @@ module git.openprivacy.ca/cwtch.im/libcwtch-go go 1.15 require ( - cwtch.im/cwtch v0.14.4 - git.openprivacy.ca/cwtch.im/server v1.4.1 + cwtch.im/cwtch v0.14.9 + git.openprivacy.ca/cwtch.im/server v1.4.2 git.openprivacy.ca/openprivacy/connectivity v1.5.0 git.openprivacy.ca/openprivacy/log v1.0.3 github.com/mutecomm/go-sqlcipher/v4 v4.4.2 - golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf // indirect -) \ No newline at end of file + 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 +) + diff --git a/go.sum b/go.sum index 87a169d..50e8c98 100644 --- a/go.sum +++ b/go.sum @@ -11,17 +11,18 @@ cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqCl cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cwtch.im/cwtch v0.14.1/go.mod h1:/fLuoYLY/7JHw6RojFojpd245CiOcU24QpWqzh9FRDI= -cwtch.im/cwtch v0.14.2 h1:Q9rUainxUcHB2+F46lxhIS5kwZLy9BhPoQI1WnKcOD4= -cwtch.im/cwtch v0.14.2/go.mod h1:/fLuoYLY/7JHw6RojFojpd245CiOcU24QpWqzh9FRDI= -cwtch.im/cwtch v0.14.3 h1:CKNBYGfKErtLDY3fUOyadTVNbI2JjOe+Ud/srydVAko= -cwtch.im/cwtch v0.14.3/go.mod h1:/fLuoYLY/7JHw6RojFojpd245CiOcU24QpWqzh9FRDI= -cwtch.im/cwtch v0.14.4 h1:QbQVzrAqczAG5tGazQvRVfN7MyQPWVN5Fwv7MzCXZs4= -cwtch.im/cwtch v0.14.4/go.mod h1:/fLuoYLY/7JHw6RojFojpd245CiOcU24QpWqzh9FRDI= +cwtch.im/cwtch v0.14.1/go.mod h1:/fLuoYLY/7JHw6RojFojpd245CiOcU24QpWqzh9FRDI= +cwtch.im/cwtch v0.14.8 h1:bybtnnCTp7utGvfIbQvdeffKmJQgGrkfgijrAfS8SQw= +cwtch.im/cwtch v0.14.8/go.mod h1:/fLuoYLY/7JHw6RojFojpd245CiOcU24QpWqzh9FRDI= +cwtch.im/cwtch v0.14.9 h1:VYXbQG6f41fCoLpLEYDAeiJSG+9Gxstl1DOk1Hv4tjM= +cwtch.im/cwtch v0.14.9/go.mod h1:/fLuoYLY/7JHw6RojFojpd245CiOcU24QpWqzh9FRDI= 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.1 h1:ZCySCYxt7rvCLdf2INFWK1xDoSexJD6sJRZ2yZ9iYHU= git.openprivacy.ca/cwtch.im/server v1.4.1/go.mod h1:gJ57TXx0cnnKN7FZSzr210KNq+WtDtBUo1zHFZ/FbTw= +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/openprivacy/bine v0.0.4 h1:CO7EkGyz+jegZ4ap8g5NWRuDHA/56KKvGySR6OBPW+c= @@ -276,7 +277,6 @@ golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHl golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= -golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs= golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= @@ -300,8 +300,9 @@ golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20201010224723-4f7140c49acb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.0.0-20210428140749-89ef3d95e781 h1:DzZ89McO9/gWPsQXS/FVKAlG02ZjaQ6AlZRBimEYOd0= golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f h1:OfiFi4JbukWwe3lzw+xunroH1mnC1e2Gy5cxNJApiSY= +golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -337,15 +338,16 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf h1:2ucpDCmfkl8Bd/FsLtiD653Wf96cW37s+iGx93zsu4k= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/lib.go b/lib.go index 3eb5a77..b2618b3 100644 --- a/lib.go +++ b/lib.go @@ -8,17 +8,23 @@ import "C" import ( "crypto/rand" - constants2 "cwtch.im/cwtch/model/constants" "encoding/json" "fmt" + + constants2 "cwtch.im/cwtch/model/constants" + + "git.openprivacy.ca/cwtch.im/libcwtch-go/features" + + // Import SQL Cipher - _ "github.com/mutecomm/go-sqlcipher/v4" "os/user" "runtime" "strconv" "strings" "unsafe" + _ "github.com/mutecomm/go-sqlcipher/v4" + "cwtch.im/cwtch/app" "cwtch.im/cwtch/event" "cwtch.im/cwtch/functionality/filesharing" @@ -96,7 +102,6 @@ func StartCwtch(appDir string, torPath string) int { if logLevel := os.Getenv("LOG_LEVEL"); strings.ToLower(logLevel) == "debug" { log.SetLevel(log.LevelDebug) } - log.Infof("StartCwtch(...)") // Quick hack check that we're being called with the correct params // On android a stale worker could be calling us with "last apps" directory. Best to abort fast so the app can make a new worker @@ -880,6 +885,28 @@ func SetMessageAttribute(profileOnion string, conversationID int, channelID int, } } +//export c_ChangePassword +func c_ChangePassword(profile_ptr *C.char, profile_len C.int, oldpassword_ptr *C.char, oldpassword_len C.int, newpassword_ptr *C.char, newpassword_len C.int, newpassword_again_ptr *C.char, newpassword_again_len C.int) { + profileOnion := C.GoStringN(profile_ptr, profile_len) + oldPassword := C.GoStringN(oldpassword_ptr, oldpassword_len) + newPassword := C.GoStringN(newpassword_ptr, newpassword_len) + newPasswordAgain := C.GoStringN(newpassword_again_ptr, newpassword_again_len) + ChangePassword(profileOnion, oldPassword, newPassword, newPasswordAgain) +} + +// ChangePassword provides a wrapper around profile.ChangePassword +func ChangePassword(profileOnion string, oldPassword string, newPassword string, newPasswordAgain string) { + profile := application.GetPeer(profileOnion) + log.Infof("changing password for %v", profileOnion) + err := profile.ChangePassword(oldPassword, newPassword, newPasswordAgain) + log.Infof("change password result %v", err) + if err == nil { + eventHandler.Push(event.NewEvent(event.AppError, map[event.Field]string{event.Data: features.ConstructResponse("changepassword", constants.StatusSuccess).Error()})) + } else { + eventHandler.Push(event.NewEvent(event.AppError, map[event.Field]string{event.Data: features.ConstructResponse("changepassword", err.Error()).Error()})) + } +} + //export c_ShutdownCwtch func c_ShutdownCwtch() { ShutdownCwtch() diff --git a/utils/eventHandler.go b/utils/eventHandler.go index 758a150..69704ba 100644 --- a/utils/eventHandler.go +++ b/utils/eventHandler.go @@ -1,21 +1,26 @@ package utils import ( + "encoding/json" + "strconv" + "cwtch.im/cwtch/app" "cwtch.im/cwtch/app/plugins" "cwtch.im/cwtch/model" "cwtch.im/cwtch/model/attr" "cwtch.im/cwtch/model/constants" + "cwtch.im/cwtch/peer" "cwtch.im/cwtch/protocol/connections" - "encoding/json" constants2 "git.openprivacy.ca/cwtch.im/libcwtch-go/constants" "git.openprivacy.ca/cwtch.im/libcwtch-go/features/groups" "git.openprivacy.ca/cwtch.im/libcwtch-go/features/servers" "git.openprivacy.ca/openprivacy/log" - "strconv" + "time" + + "cwtch.im/cwtch/event" + "cwtch.im/cwtch/functionality/filesharing" ) -import "cwtch.im/cwtch/event" type EventProfileEnvelope struct { Event event.Event @@ -96,26 +101,25 @@ func (eh *EventHandler) handleAppBusEvent(e *event.Event) string { if e.Data[event.Created] == event.True { profile.SetScopedZonedAttribute(attr.PublicScope, attr.ProfileZone, constants2.Picture, ImageToString(NewImage(RandomProfileImage(onion), TypeImageDistro))) } - if e.Data[event.Created] == event.True { - profile.SetScopedZonedAttribute(attr.LocalScope, attr.ProfileZone, constants2.PeerOnline, event.False) - eh.app.AddPeerPlugin(onion, plugins.CONNECTIONRETRY) - eh.app.AddPeerPlugin(onion, plugins.NETWORKCHECK) - // If the user has chosen to block unknown profiles - // then explicitly configure the protocol engine to do so.. - if ReadGlobalSettings().BlockUnknownConnections { - profile.BlockUnknownConnections() - } else { - // For completeness - profile.AllowUnknownConnections() - } + profile.SetScopedZonedAttribute(attr.LocalScope, attr.ProfileZone, constants2.PeerOnline, event.False) + eh.app.AddPeerPlugin(onion, plugins.CONNECTIONRETRY) + eh.app.AddPeerPlugin(onion, plugins.NETWORKCHECK) - // Start up the Profile - profile.Listen() - profile.StartPeersConnections() - if _, err := groups.ExperimentGate(ReadGlobalSettings().Experiments); err == nil { - profile.StartServerConnections() - } + // If the user has chosen to block unknown profiles + // then explicitly configure the protocol engine to do so.. + if ReadGlobalSettings().BlockUnknownConnections { + profile.BlockUnknownConnections() + } else { + // For completeness + profile.AllowUnknownConnections() + } + + // Start up the Profile + profile.Listen() + profile.StartPeersConnections() + if _, err := groups.ExperimentGate(ReadGlobalSettings().Experiments); err == nil { + profile.StartServerConnections() } online, _ := profile.GetScopedZonedAttribute(attr.LocalScope, attr.ProfileZone, constants2.PeerOnline) @@ -263,10 +267,16 @@ func (eh *EventHandler) handleProfileEvent(ev *EventProfileEnvelope) string { ev.Event.Data["Nick"], exists = ci.GetAttribute(attr.PublicScope, attr.ProfileZone, constants.Name) if !exists { ev.Event.Data["Nick"] = ev.Event.Data["RemotePeer"] + // If we dont have a name val for a peer, but they have sent us a message, we might be approved now, re-ask + profile.SendScopedZonedGetValToContact(ci.ID, attr.PublicScope, attr.ProfileZone, constants.Name) + profile.SendScopedZonedGetValToContact(ci.ID, attr.PublicScope, attr.ProfileZone, constants2.Picture) } } ev.Event.Data["Picture"] = RandomProfileImage(ev.Event.Data["RemotePeer"]) + if ci.Accepted { + handleImagePreviews(profile, &ev.Event, ci.ID, ci.ID) + } case event.NewMessageFromGroup: // only needs contact nickname and picture, for displaying on popup notifications ci, err := profile.FetchConversationInfo(ev.Event.Data["RemotePeer"]) @@ -283,6 +293,10 @@ func (eh *EventHandler) handleProfileEvent(ev *EventProfileEnvelope) string { ev.Event.Data["Picture"] = RandomProfileImage(ev.Event.Data[event.RemotePeer]) conversationID, _ := strconv.Atoi(ev.Event.Data[event.ConversationID]) profile.SetConversationAttribute(conversationID, attr.LocalScope.ConstructScopedZonedPath(attr.ProfileZone.ConstructZonedPath(constants2.Archived)), event.False) + + if ci != nil && ci.Accepted { + handleImagePreviews(profile, &ev.Event, conversationID, ci.ID) + } case event.PeerAcknowledgement: ci, err := profile.FetchConversationInfo(ev.Event.Data["RemotePeer"]) if ci != nil && err == nil { @@ -370,7 +384,7 @@ func (eh *EventHandler) handleProfileEvent(ev *EventProfileEnvelope) string { if exists && attr.IntoScope(scope) == attr.PublicScope { zone, path := attr.ParseZone(path) - if _, err := profile.GetConversationAttribute(conversationID, attr.LocalScope.ConstructScopedZonedPath(zone.ConstructZonedPath(path))); err != nil { + if val, err := profile.GetConversationAttribute(conversationID, attr.LocalScope.ConstructScopedZonedPath(zone.ConstructZonedPath(path))); err != nil && val != "" { // we have a locally set override, don't pass this remote set public scope update to UI return "" } @@ -407,10 +421,10 @@ func (eh *EventHandler) startHandlingPeer(onion string) { eventBus.Subscribe(event.GroupCreated, q) eventBus.Subscribe(event.NewGroup, q) eventBus.Subscribe(event.DeleteGroup, q) - eventBus.Subscribe(event.SendMessageToGroupError, q) - eventBus.Subscribe(event.SendMessageToPeerError, q) eventBus.Subscribe(event.ServerStateChange, q) eventBus.Subscribe(event.PeerStateChange, q) + eventBus.Subscribe(event.ChangePasswordSuccess, q) + eventBus.Subscribe(event.ChangePasswordError, q) eventBus.Subscribe(event.NewRetValMessageFromPeer, q) eventBus.Subscribe(event.ShareManifest, q) eventBus.Subscribe(event.ManifestSizeReceived, q) @@ -454,3 +468,28 @@ func getLastMessageTime(conversationMessages []model.ConversationMessage) int { } return int(time.Unix()) } + +// handleImagePreviews checks settings and, if appropriate, auto-downloads any images +func handleImagePreviews(profile peer.CwtchPeer, ev *event.Event, conversationID, senderID int) { + settings := ReadGlobalSettings() + fh, err := filesharing.PreviewFunctionalityGate(settings.Experiments) + if err == nil { + var cm model.MessageWrapper + err := json.Unmarshal([]byte(ev.Data[event.Data]), &cm) + if err == nil && cm.Overlay == model.OverlayFileSharing { + var fm filesharing.OverlayMessage + err = json.Unmarshal([]byte(cm.Data), &fm) + if err == nil { + if fm.ShouldAutoDL() { + basepath := settings.DownloadPath + fp, mp := filesharing.GenerateDownloadPath(basepath, fm.Name) + log.Debugf("autodownloading file!") + ev.Data["Auto"] = constants.True + mID, _ := strconv.Atoi(ev.Data["Index"]) + profile.UpdateMessageAttribute(conversationID, 0, mID, constants.AttrDownloaded, constants.True) + fh.DownloadFile(profile, senderID, fp, mp, fm.FileKey()) + } + } + } + } +} diff --git a/utils/settings.go b/utils/settings.go index 1786729..cf4ee70 100644 --- a/utils/settings.go +++ b/utils/settings.go @@ -1,15 +1,17 @@ package utils import ( - "cwtch.im/cwtch/event" - "cwtch.im/cwtch/storage/v1" "sync" + "cwtch.im/cwtch/event" + "cwtch.im/cwtch/storage/v1" + "encoding/json" - "git.openprivacy.ca/openprivacy/log" "io/ioutil" "os" "path" + + "git.openprivacy.ca/openprivacy/log" ) const ( @@ -37,6 +39,7 @@ type GlobalSettings struct { FirstTime bool UIColumnModePortrait string UIColumnModeLandscape string + DownloadPath string } var DefaultGlobalSettings = GlobalSettings{ @@ -51,6 +54,7 @@ var DefaultGlobalSettings = GlobalSettings{ StreamerMode: false, UIColumnModePortrait: "DualpaneMode.Single", UIColumnModeLandscape: "DualpaneMode.CopyPortrait", + DownloadPath: "", } func InitGlobalSettingsFile(directory string, password string) error {