diff --git a/client/dbmessage.go b/client/dbmessage.go index 40339d8..d988381 100644 --- a/client/dbmessage.go +++ b/client/dbmessage.go @@ -14,7 +14,7 @@ func DbMessageToInternalUserMessage(id int64, dbFile string, dbm *meowlib.DbMess ium.Outbound = false } ium.Message = string(dbm.Data) - ium.ConversationStatus = dbm.Status + ium.Status = dbm.Status ium.Contact = dbm.Contact ium.CurrentLocation = dbm.CurrentLocation ium.Messagetype = dbm.Type @@ -23,6 +23,19 @@ func DbMessageToInternalUserMessage(id int64, dbFile string, dbm *meowlib.DbMess return &ium } +func InternalUserMessageToDbMessage(ium *InternalUserMessage) *meowlib.DbMessage { + var dbm meowlib.DbMessage + dbm.Outbound = ium.Outbound + dbm.Type = ium.Messagetype + dbm.Data = []byte(ium.Message) + dbm.Appdata = ium.Appdata + dbm.Contact = ium.Contact + dbm.CurrentLocation = ium.CurrentLocation + dbm.Status = ium.Status + dbm.FilePaths = ium.FilePaths + return &dbm +} + func UserMessageToDbMessage(outbound bool, um *meowlib.UserMessage, filepaths []string) *meowlib.DbMessage { var dbm meowlib.DbMessage dbm.Outbound = outbound diff --git a/client/helpers/messageHelper.go b/client/helpers/messageHelper.go index a20af61..77904f6 100644 --- a/client/helpers/messageHelper.go +++ b/client/helpers/messageHelper.go @@ -51,7 +51,7 @@ func PrepareUserMessage(message string, srvuid string, peer_idx int, replyToUid } -func SendAck(messageUid string, srvuid string, peer_idx int, received int64, processed int64) ([]byte, string, error) { +func BuildAckMessage(messageUid string, srvuid string, peer_idx int, received int64, processed int64) ([]byte, string, error) { peer := client.GetConfig().GetIdentity().Peers[peer_idx] srv, err := client.GetConfig().GetIdentity().MessageServers.LoadServer(srvuid) @@ -77,10 +77,10 @@ func SendAck(messageUid string, srvuid string, peer_idx int, received int64, pro if err != nil { return nil, "PrepareServerMessage : ProcessOutboundMessage", err } - // Store message - err = peer.StoreMessage(usermessage, nil) - if err != nil { - return nil, "PrepareServerMessage : StoreMessage", err - } + return data, "", nil } + +func ReadAckMessageResponse() { + //! update the status in message store +} diff --git a/client/message.go b/client/internalusermessage.go similarity index 95% rename from client/message.go rename to client/internalusermessage.go index 11c0fd1..d84f260 100644 --- a/client/message.go +++ b/client/internalusermessage.go @@ -6,7 +6,7 @@ type InternalUserMessage struct { Outbound bool `json:"outbound"` Messagetype string `json:"messagetype,omitempty"` Message string `json:"message,omitempty"` - ConversationStatus *meowlib.ConversationStatus `json:"conversation_status,omitempty"` + Status *meowlib.ConversationStatus `json:"conversation_status,omitempty"` Contact *meowlib.ContactCard `json:"contact,omitempty"` ServerDeliveryUuid string `json:"server_delivery_uuid,omitempty"` ServerDeliveryTimestamp int64 `json:"server_delivery_timestamp,omitempty"` @@ -28,7 +28,7 @@ func InternalUserMessageFromUserMessage(peer *Peer, msg *meowlib.UserMessage) *I } iu.Messagetype = msg.Type iu.Message = string(msg.Data) - iu.ConversationStatus = msg.Status + iu.Status = msg.Status iu.Contact = msg.Contact return iu } diff --git a/client/messagestorage.go b/client/messagestorage.go index 254827b..ba5a11e 100644 --- a/client/messagestorage.go +++ b/client/messagestorage.go @@ -225,9 +225,7 @@ func GetMessagesHistory(peer *Peer, inAppMsgCount int, lastDbId int, wantMore in return messages, nil } -// Get old messages from a peer -func GetMessagePreview(peer *Peer, dbFile string, dbId int64, password string) ([]byte, error) { - +func GetDbMessage(dbFile string, dbId int64, password string) (*meowlib.DbMessage, error) { // There fileidx should provide the db that we need (unless wantMore overlaps the next DB) db, _ := sql.Open("sqlite3", filepath.Join(GetConfig().StoragePath, GetConfig().GetIdentity().Uuid, dbFile+GetConfig().DbSuffix)) // Open the created SQLite File defer db.Close() @@ -261,9 +259,44 @@ func GetMessagePreview(peer *Peer, dbFile string, dbId int64, password string) ( } } + return &dbm, nil +} + +func UpdateDbMessage(dbm *meowlib.DbMessage, dbFile string, dbId int64, password string) error { + db, _ := sql.Open("sqlite3", filepath.Join(GetConfig().StoragePath, GetConfig().GetIdentity().Uuid, dbFile+GetConfig().DbSuffix)) // Open the created SQLite File + defer db.Close() + // Encrypt message + out, err := proto.Marshal(dbm) + if err != nil { + return err + } + encData, err := meowlib.SymEncrypt(password, out) + if err != nil { + return err + } + // Insert message + updateMessageSQL := `UPDATE message SET m=? WHERE id=?` + statement, err := db.Prepare(updateMessageSQL) // Prepare statement. + if err != nil { + return err + } + _, err = statement.Exec(encData, dbId) + if err != nil { + return err + } + return nil +} + +// Get old messages from a peer +func GetMessagePreview(dbFile string, dbId int64, password string) ([]byte, error) { + dbm, err := GetDbMessage(dbFile, dbId, password) + if err != nil { + return nil, err + } return FilePreview(dbm.FilePaths[0], password) } +// decrypt the a file and returns the raw content func FilePreview(filename string, password string) ([]byte, error) { // get the hidden file encData, err := os.ReadFile(filename) @@ -278,7 +311,7 @@ func FilePreview(filename string, password string) ([]byte, error) { return data, nil } -// make an image from the files content (loads the first image, or build a more complex view) +// return the raw content from the files content (loads the first image, or build a more complex view) func InternalUserMessagePreview(msg *InternalUserMessage, password string) ([]byte, error) { // get the hidden file name if len(msg.FilePaths) == 0 { @@ -296,7 +329,6 @@ func getMessageCount(dbid string) (int, error) { if err != nil { return 0, err } - return count, nil } diff --git a/client/peerstorage.go b/client/peerstorage.go index aa7cd42..6a51a2f 100644 --- a/client/peerstorage.go +++ b/client/peerstorage.go @@ -6,7 +6,9 @@ package client import ( "crypto/sha256" "encoding/json" + "errors" "path/filepath" + "sort" "forge.redroom.link/yves/meowlib" "github.com/dgraph-io/badger" @@ -18,7 +20,7 @@ type PeerStorage struct { cache map[string]*Peer } -// Open a badger database from struct PeerStorage +// Open the badger database from struct PeerStorage func (ps *PeerStorage) open() error { opts := badger.DefaultOptions(filepath.Join(GetConfig().StoragePath, GetConfig().GetIdentity().Uuid, ps.DbFile)) @@ -31,7 +33,7 @@ func (ps *PeerStorage) open() error { return nil } -// Store function StorePeer stores a peer in a badger database with Peer.Uid as key +// Store function StorePeer stores a peer in the badger database with Peer.Uid as key func (ps *PeerStorage) StorePeer(peer *Peer) error { err := ps.open() if err != nil { @@ -60,7 +62,7 @@ func (ps *PeerStorage) StorePeer(peer *Peer) error { } -// LoadPeer function loads a Peer from a badger database with Peer.GetUid() as key +// LoadPeer function loads a Peer from the badger database with Peer.GetUid() as key func (ps *PeerStorage) LoadPeer(uid string, password string) (*Peer, error) { var peer Peer err := ps.open() @@ -86,7 +88,7 @@ func (ps *PeerStorage) LoadPeer(uid string, password string) (*Peer, error) { return &peer, err } -// DeletePeer function deletes a Peer from a badger database with Peer.GetUid() as key +// DeletePeer function deletes a Peer from the badger database with Peer.GetUid() as key func (ps *PeerStorage) DeletePeer(uid string) error { err := ps.open() if err != nil { @@ -100,8 +102,8 @@ func (ps *PeerStorage) DeletePeer(uid string) error { }) } -// LoadAllPeers function loads all Peers from a badger database -func (ps *PeerStorage) LoadAllPeers(password string) ([]*Peer, error) { +// LoadPeers function loads Peers from the badger database with a specific password +func (ps *PeerStorage) LoadPeers(password string) ([]*Peer, error) { var peers []*Peer err := ps.open() if err != nil { @@ -125,48 +127,104 @@ func (ps *PeerStorage) LoadAllPeers(password string) ([]*Peer, error) { }) if err != nil { peers = append(peers, &sc) + ps.cache[sc.Uid] = &sc } } return nil }) + // Sort peers based on peer.Name + sort.Slice(peers, func(i, j int) bool { + return peers[i].Name < peers[j].Name + }) return peers, err } -// LoadPeersFromUids function loads Peers with id in []Uid parameter from a badger database -func (ps *PeerStorage) LoadPeersFromUids(uids []string, password string) ([]*Peer, error) { - var peers []*Peer - err := ps.open() - if err != nil { - return nil, err +// GetPeers function returns all peers from the cache as a sorted array +func (ps *PeerStorage) GetPeers() ([]*Peer, error) { + peers := make([]*Peer, 0, len(ps.cache)) + for _, peer := range ps.cache { + peers = append(peers, peer) } - defer ps.close() - err = ps.db.View(func(txn *badger.Txn) error { - for _, uid := range uids { - shakey := sha256.Sum256([]byte(uid)) - key := shakey[:] - item, err := txn.Get(key) - if err != nil { - return err - } - var sc Peer - err = item.Value(func(val []byte) error { - jsonsrv, err := meowlib.SymDecrypt(password, val) - if err != nil { - return err - } - return json.Unmarshal(jsonsrv, &sc) - }) - if err == nil { - peers = append(peers, &sc) - } - - } - return nil + // Sort peers based on peer.Name + sort.Slice(peers, func(i, j int) bool { + return peers[i].Name < peers[j].Name }) - return peers, err + return peers, nil } -// close a badger database +// close the badger database func (ps *PeerStorage) close() { ps.db.Close() } + +func (ps *PeerStorage) GetFromPublicKey(publickey string) *Peer { + for _, peer := range ps.cache { + if peer.ContactPublicKey == publickey { + return peer + } + } + return nil +} + +func (ps *PeerStorage) GetFromInvitationId(invitationId string) *Peer { + for _, peer := range ps.cache { + if peer.InvitationId == invitationId { + return peer + } + } + return nil +} + +func (ps *PeerStorage) GetFromMyLookupKey(publickey string) *Peer { + for _, peer := range ps.cache { + if peer.MyLookupKp.Public == publickey { + return peer + } + } + return nil +} + +func (ps *PeerStorage) GetFromName(name string) *Peer { + for _, peer := range ps.cache { + if peer.Name == name { + return peer + } + } + return nil +} + +func (ps *PeerStorage) GetFromUid(uid string) *Peer { + return ps.cache[uid] +} + +// Checks if the received contact card is an answer to an invitation, returns true if it is, and the proposed and received nicknames +func (ps *PeerStorage) CheckInvitation(ReceivedContact *meowlib.ContactCard) (isAnswer bool, proposedNick string, receivedNick string, invitationMessage string) { + // invitation Id found, this is an answer to an invitation + for _, p := range ps.cache { + if p.InvitationId == ReceivedContact.InvitationId { + return true, p.Name, ReceivedContact.Name, ReceivedContact.InvitationMessage + } + } + // it's an invitation + return false, "", ReceivedContact.Name, ReceivedContact.InvitationMessage +} + +// Finalizes an invitation, returns nil if successful +func (ps *PeerStorage) FinalizeInvitation(ReceivedContact *meowlib.ContactCard) error { + for i, p := range ps.cache { + if p.InvitationId == ReceivedContact.InvitationId { + //id.Peers[i].Name = ReceivedContact.Name + ps.cache[i].ContactEncryption = ReceivedContact.EncryptionPublicKey + ps.cache[i].ContactLookupKey = ReceivedContact.LookupPublicKey + ps.cache[i].ContactPublicKey = ReceivedContact.ContactPublicKey + srvs := []string{} + for srv := range ReceivedContact.PullServers { + srvs = append(srvs, ReceivedContact.PullServers[srv].GetUid()) + } + ps.cache[i].ContactPullServers = srvs + ps.StorePeer(ps.cache[i]) + return nil + } + } + return errors.New("no matching contact found for invitationId " + ReceivedContact.InvitationId) +}