Import and Export Profile
continuous-integration/drone/pr Build is passing Details

This commit also adds some guard rails around calling functions without a proper backing profile.
This commit is contained in:
Sarah Jamie Lewis 2022-03-09 14:33:44 -08:00
parent 68c976107d
commit 31dda072e5
3 changed files with 164 additions and 141 deletions

2
go.mod
View File

@ -3,7 +3,7 @@ module git.openprivacy.ca/cwtch.im/libcwtch-go
go 1.15
require (
cwtch.im/cwtch v0.16.0
cwtch.im/cwtch v0.16.1
git.openprivacy.ca/cwtch.im/server v1.4.2
git.openprivacy.ca/openprivacy/connectivity v1.8.1
git.openprivacy.ca/openprivacy/log v1.0.3

3
go.sum
View File

@ -13,6 +13,8 @@ cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiy
cwtch.im/cwtch v0.14.9/go.mod h1:/fLuoYLY/7JHw6RojFojpd245CiOcU24QpWqzh9FRDI=
cwtch.im/cwtch v0.16.0 h1:gHSbt73K1gE5crOdEjMjl9hv6zyNnsMVreRkEU9r6kY=
cwtch.im/cwtch v0.16.0/go.mod h1:lG9e5RUib+SbX2XsjWtHKJWz9geoIglSAq55LrCm8Io=
cwtch.im/cwtch v0.16.1 h1:V9fmJthou0s6zOqCLi+bxj/39HB58bdPe5n/npaBQBc=
cwtch.im/cwtch v0.16.1/go.mod h1:lG9e5RUib+SbX2XsjWtHKJWz9geoIglSAq55LrCm8Io=
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=
@ -274,6 +276,7 @@ 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=

54
lib.go
View File

@ -535,8 +535,10 @@ func c_AcceptConversation(profilePtr *C.char, profileLen C.int, conversation_id
// for further action (e.g. messaging / connecting to the server / joining the group etc.)
func AcceptConversation(profileOnion string, conversationID int) {
profile := application.GetPeer(profileOnion)
if profile != nil {
profile.AcceptConversation(conversationID)
}
}
//export c_BlockContact
func c_BlockContact(profilePtr *C.char, profileLen C.int, conversation_id C.int) {
@ -545,8 +547,10 @@ func c_BlockContact(profilePtr *C.char, profileLen C.int, conversation_id C.int)
func BlockContact(profileOnion string, conversationID int) {
profile := application.GetPeer(profileOnion)
if profile != nil {
profile.BlockConversation(conversationID)
}
}
//export c_UnblockContact
func c_UnblockContact(profilePtr *C.char, profileLen C.int, conversation_id C.int) {
@ -555,8 +559,10 @@ func c_UnblockContact(profilePtr *C.char, profileLen C.int, conversation_id C.in
func UnblockContact(profileOnion string, conversationID int) {
profile := application.GetPeer(profileOnion)
if profile != nil {
profile.UnblockConversation(conversationID)
}
}
//export c_GetMessage
// the pointer returned from this function **must** be Freed by c_Free
@ -584,6 +590,7 @@ func GetMessage(profileOnion string, conversationID int, messageIndex int) strin
// these requests complete almost immediately v.s. being stalled for seconds to minutes on large groups.
if application != nil {
profile := application.GetPeer(profileOnion)
if profile != nil {
messages, err := profile.GetMostRecentMessages(conversationID, 0, messageIndex, 1)
if err == nil && len(messages) == 1 {
time, _ := time.Parse(time.RFC3339Nano, messages[0].Attr[constants2.AttrSentTimestamp])
@ -600,6 +607,7 @@ func GetMessage(profileOnion string, conversationID int, messageIndex int) strin
message.ContentHash = model.CalculateContentHash(messages[0].Attr[constants2.AttrAuthor], messages[0].Body)
}
}
}
bytes, _ := json.Marshal(message)
return string(bytes)
}
@ -620,6 +628,7 @@ func GetMessageByID(profileOnion string, conversationID int, messageID int) stri
// these requests complete almost immediately v.s. being stalled for seconds to minutes on large groups.
if application != nil {
profile := application.GetPeer(profileOnion)
if profile != nil {
dbmessage, attr, err := profile.GetChannelMessage(conversationID, 0, messageID)
if err == nil {
time, _ := time.Parse(time.RFC3339Nano, attr[constants2.AttrSentTimestamp])
@ -636,6 +645,7 @@ func GetMessageByID(profileOnion string, conversationID int, messageID int) stri
message.ContentHash = model.CalculateContentHash(attr[constants2.AttrAuthor], dbmessage)
}
}
}
bytes, _ := json.Marshal(message)
return string(bytes)
}
@ -652,6 +662,7 @@ func GetMessagesByContentHash(profileOnion string, handle int, contentHash strin
var message EnhancedMessage
if application != nil {
profile := application.GetPeer(profileOnion)
if profile != nil {
offset, err := profile.GetChannelMessageByContentHash(handle, 0, contentHash)
if err == nil {
messages, err := profile.GetMostRecentMessages(handle, 0, offset, 1)
@ -674,6 +685,7 @@ func GetMessagesByContentHash(profileOnion string, handle int, contentHash strin
}
}
}
}
bytes, _ := json.Marshal(message)
return string(bytes)
}
@ -693,8 +705,10 @@ func c_SendMessage(profile_ptr *C.char, profile_len C.int, conversation_id C.int
func SendMessage(profileOnion string, conversationID int, msg string) {
profile := application.GetPeer(profileOnion)
if profile != nil {
profile.SendMessage(conversationID, msg)
}
}
//export c_SendInvitation
func c_SendInvitation(profile_ptr *C.char, profile_len C.int, conversation_id C.int, target_id C.int) {
@ -707,8 +721,10 @@ func c_SendInvitation(profile_ptr *C.char, profile_len C.int, conversation_id C.
// For groups, the profile must already have `target` as a contact.
func SendInvitation(profileOnion string, conversationID int, targetID int) {
profile := application.GetPeer(profileOnion)
if profile != nil {
profile.SendInviteToConversation(conversationID, targetID)
}
}
//export c_ShareFile
func c_ShareFile(profile_ptr *C.char, profile_len C.int, conversation_id C.int, filepath_ptr *C.char, filepath_len C.int) {
@ -719,6 +735,7 @@ func c_ShareFile(profile_ptr *C.char, profile_len C.int, conversation_id C.int,
func ShareFile(profileOnion string, conversationID int, sharefilepath string) {
profile := application.GetPeer(profileOnion)
if profile != nil {
fh, err := filesharing.FunctionalityGate(utils.ReadGlobalSettings().Experiments)
if err != nil {
log.Errorf("file sharing error: %v", err)
@ -735,6 +752,7 @@ func ShareFile(profileOnion string, conversationID int, sharefilepath string) {
}
}
}
}
//export c_DownloadFile
func c_DownloadFile(profile_ptr *C.char, profile_len C.int, conversation_id C.int, filepath_ptr *C.char, filepath_len C.int, manifestpath_ptr *C.char, manifestpath_len C.int, filekey_ptr *C.char, filekey_len C.int) {
@ -747,6 +765,7 @@ func c_DownloadFile(profile_ptr *C.char, profile_len C.int, conversation_id C.in
func DownloadFile(profileOnion string, conversationID int, filepath, manifestpath, filekey string) {
profile := application.GetPeer(profileOnion)
if profile != nil {
fh, err := filesharing.FunctionalityGate(utils.ReadGlobalSettings().Experiments)
if err != nil {
log.Errorf("file sharing error: %v", err)
@ -755,6 +774,7 @@ func DownloadFile(profileOnion string, conversationID int, filepath, manifestpat
fh.DownloadFile(profile, conversationID, filepath, manifestpath, filekey, files.MaxManifestSize*files.DefaultChunkSize)
}
}
}
//export c_CheckDownloadStatus
func c_CheckDownloadStatus(profilePtr *C.char, profileLen C.int, fileKeyPtr *C.char, fileKeyLen C.int) {
@ -763,6 +783,7 @@ func c_CheckDownloadStatus(profilePtr *C.char, profileLen C.int, fileKeyPtr *C.c
func CheckDownloadStatus(profileOnion, fileKey string) {
profile := application.GetPeer(profileOnion)
if profile != nil {
path, _ := profile.GetScopedZonedAttribute(attr.LocalScope, attr.FilesharingZone, fmt.Sprintf("%s.path", fileKey))
if value, exists := profile.GetScopedZonedAttribute(attr.LocalScope, attr.FilesharingZone, fmt.Sprintf("%s.complete", fileKey)); exists && value == event.True {
eventHandler.Push(event.NewEvent(event.FileDownloaded, map[event.Field]string{
@ -782,6 +803,7 @@ func CheckDownloadStatus(profileOnion, fileKey string) {
}))
}
}
}
//export c_VerifyOrResumeDownload
func c_VerifyOrResumeDownload(profile_ptr *C.char, profile_len C.int, conversation_id C.int, filekey_ptr *C.char, filekey_len C.int) {
@ -792,6 +814,7 @@ func c_VerifyOrResumeDownload(profile_ptr *C.char, profile_len C.int, conversati
func VerifyOrResumeDownload(profileOnion string, conversationID int, fileKey string) {
profile := application.GetPeer(profileOnion)
if profile != nil {
if manifestFilePath, exists := profile.GetScopedZonedAttribute(attr.LocalScope, attr.FilesharingZone, fmt.Sprintf("%v.manifest", fileKey)); exists {
if downloadfilepath, exists := profile.GetScopedZonedAttribute(attr.LocalScope, attr.FilesharingZone, fmt.Sprintf("%s.path", fileKey)); exists {
log.Infof("resuming %s", fileKey)
@ -803,6 +826,7 @@ func VerifyOrResumeDownload(profileOnion string, conversationID int, fileKey str
log.Errorf("no stored manifest path found for %s", fileKey)
}
}
}
//export c_ResetTor
func c_ResetTor() {
@ -834,6 +858,7 @@ func c_CreateGroup(profile_ptr *C.char, profile_len C.int, server_ptr *C.char, s
// CreateGroup takes in a profile and server in addition to a name and creates a new group.
func CreateGroup(profileHandle string, server string, name string) {
profile := application.GetPeer(profileHandle)
if profile != nil {
_, err := groups.ExperimentGate(utils.ReadGlobalSettings().Experiments)
if err == nil {
conversationID, err := profile.StartGroup(name, server)
@ -844,6 +869,7 @@ func CreateGroup(profileHandle string, server string, name string) {
}
}
}
}
//export c_DeleteProfile
func c_DeleteProfile(profile_ptr *C.char, profile_len C.int, password_ptr *C.char, password_len C.int) {
@ -872,8 +898,10 @@ func c_ArchiveConversation(profile_ptr *C.char, profile_len C.int, conversation_
// ArchiveConversation sets the conversation to archived
func ArchiveConversation(profileHandle string, conversationID int) {
profile := application.GetPeer(profileHandle)
if profile != nil {
profile.SetConversationAttribute(conversationID, attr.LocalScope.ConstructScopedZonedPath(attr.ProfileZone.ConstructZonedPath(constants.Archived)), constants2.True)
}
}
//export c_DeleteContact
func c_DeleteContact(profile_ptr *C.char, profile_len C.int, conversation_id C.int) {
@ -884,8 +912,10 @@ func c_DeleteContact(profile_ptr *C.char, profile_len C.int, conversation_id C.i
// DeleteContact removes all trace of the contact from the profile
func DeleteContact(profileHandle string, conversationID int) {
profile := application.GetPeer(profileHandle)
if profile != nil {
profile.DeleteConversation(conversationID)
}
}
//export c_ImportBundle
func c_ImportBundle(profile_ptr *C.char, profile_len C.int, bundle_ptr *C.char, bundle_len C.int) {
@ -898,6 +928,7 @@ func c_ImportBundle(profile_ptr *C.char, profile_len C.int, bundle_ptr *C.char,
// different formats (e.g. a peer address, a group invite, a server key bundle, or a combination)
func ImportBundle(profileOnion string, bundle string) {
profile := application.GetPeer(profileOnion)
if profile != nil {
response := profile.ImportBundle(bundle)
// We might have added a new server, so refresh the server list if applicable...
@ -910,6 +941,7 @@ func ImportBundle(profileOnion string, bundle string) {
eventHandler.Push(event.NewEvent(event.AppError, map[event.Field]string{event.Data: response.Error()}))
}
}
//export c_SetProfileAttribute
func c_SetProfileAttribute(profile_ptr *C.char, profile_len C.int, key_ptr *C.char, key_len C.int, val_ptr *C.char, val_len C.int) {
@ -926,6 +958,7 @@ func c_SetProfileAttribute(profile_ptr *C.char, profile_len C.int, key_ptr *C.ch
// Key must have the format zone.key where Zone is defined in Cwtch. Unknown zones are not permitted.
func SetProfileAttribute(profileOnion string, key string, value string) {
profile := application.GetPeer(profileOnion)
if profile != nil {
zone, key := attr.ParseZone(key)
// TODO We only allow public.profile.zone to be set for now.
@ -936,6 +969,7 @@ func SetProfileAttribute(profileOnion string, key string, value string) {
log.Errorf("attempted to set an attribute with an unknown zone: %v", key)
}
}
}
//export c_SetConversationAttribute
func c_SetConversationAttribute(profile_ptr *C.char, profile_len C.int, conversation_id C.int, key_ptr *C.char, key_len C.int, val_ptr *C.char, val_len C.int) {
@ -988,6 +1022,7 @@ func c_ChangePassword(profile_ptr *C.char, profile_len C.int, oldpassword_ptr *C
// ChangePassword provides a wrapper around profile.ChangePassword
func ChangePassword(profileOnion string, oldPassword string, newPassword string, newPasswordAgain string) {
profile := application.GetPeer(profileOnion)
if profile != nil {
log.Infof("changing password for %v", profileOnion)
err := profile.ChangePassword(oldPassword, newPassword, newPasswordAgain)
log.Infof("change password result %v", err)
@ -997,6 +1032,7 @@ func ChangePassword(profileOnion string, oldPassword string, newPassword string,
eventHandler.Push(event.NewEvent(event.AppError, map[event.Field]string{event.Data: features.ConstructResponse("changepassword", err.Error()).Error()}))
}
}
}
//export c_ExportProfile
func c_ExportProfile(profile_ptr *C.char, profile_len C.int, file_ptr *C.char, file_len C.int) {
@ -1008,15 +1044,9 @@ func c_ExportProfile(profile_ptr *C.char, profile_len C.int, file_ptr *C.char, f
// ExportProfile provides a wrapper around profile.ExportProfile
func ExportProfile(profileOnion string, file string) {
profile := application.GetPeer(profileOnion)
if profile != nil {
profile.Export(file)
}
//export c_ExportProfile
func c_Import(profile_ptr *C.char, profile_len C.int, file_ptr *C.char, file_len C.int) {
profileOnion := C.GoStringN(profile_ptr, profile_len)
file := C.GoStringN(file_ptr, file_len)
ExportProfile(profileOnion, file)
}
//export c_ImportProfile
@ -1035,15 +1065,6 @@ func ImportProfile(exportedCwtchFile string, pass string) string {
return err.Error()
}
//export c_SetMessageAttribute
func c_SetMessageAttribute(profile_ptr *C.char, profile_len C.int, conversation_id C.int, channel_id C.int, message_id C.int, key_ptr *C.char, key_len C.int, val_ptr *C.char, val_len C.int) {
profileOnion := C.GoStringN(profile_ptr, profile_len)
key := C.GoStringN(key_ptr, key_len)
value := C.GoStringN(val_ptr, val_len)
SetMessageAttribute(profileOnion, int(conversation_id), int(channel_id), int(message_id), key, value)
}
//export c_ShutdownCwtch
func c_ShutdownCwtch() {
ShutdownCwtch()
@ -1153,7 +1174,6 @@ func DeleteServer(onion string, currentPassword string) {
}
}
//export c_LaunchServers
func c_LaunchServers() {
LaunchServers()