diff --git a/app/app.go b/app/app.go index b3dc392..e5b91e6 100644 --- a/app/app.go +++ b/app/app.go @@ -160,21 +160,16 @@ func (ac *applicationCore) LoadProfiles(password string, timeline bool, loadProf // Attempt to load an encrypted database profileDirectory := path.Join(ac.directory, "profiles", file.Name()) profile, err := peer.FromEncryptedDatabase(profileDirectory, password) - if err == nil { // return the load the profile... + log.Infof("loading profile from new-type storage database...") loadProfileFn(profile) - } - - // On failure attempt to load a legacy profile - if err != nil { - eventBus := event.NewEventManager() - - profileStore, err := storage.LoadProfileWriterStore(eventBus, profileDirectory, password) + } else { // On failure attempt to load a legacy profile + profileStore, err := storage.LoadProfileWriterStore(profileDirectory, password) if err != nil { continue } - + log.Infof("found legacy profile. importing to new database structure...") legacyProfile := profileStore.GetProfileCopy(timeline) cps, err := peer.CreateEncryptedStore(profileDirectory, password) diff --git a/model/constants/attributes.go b/model/constants/attributes.go index 64c6917..d3385a6 100644 --- a/model/constants/attributes.go +++ b/model/constants/attributes.go @@ -30,6 +30,9 @@ const True = "true" // False - false const False = "false" +// AttrAuthor - conversation attribute for author of the message - referenced by pub key rather than conversation id because of groups. +const AttrAuthor = "author" + // AttrAck - conversation attribute for acknowledgement status const AttrAck = "ack" diff --git a/model/group.go b/model/group.go index 3e1b6ff..2356404 100644 --- a/model/group.go +++ b/model/group.go @@ -33,6 +33,7 @@ type Group struct { GroupName string GroupKey [32]byte GroupServer string + Attributes map[string]string //legacy to not use Version int Timeline Timeline `json:"-"` LocalID string diff --git a/peer/cwtch_peer.go b/peer/cwtch_peer.go index 05f7b73..6f21f45 100644 --- a/peer/cwtch_peer.go +++ b/peer/cwtch_peer.go @@ -27,6 +27,7 @@ import ( ) const lastKnownSignature = "LastKnowSignature" +const lastReceivedSignature = "LastReceivedSignature" var autoHandleableEvents = map[event.Type]bool{event.EncryptedGroupMessage: true, event.PeerStateChange: true, event.ServerStateChange: true, event.NewGroupInvite: true, event.NewMessageFromPeer: true, @@ -160,7 +161,7 @@ func (cp *cwtchPeer) SendMessage(conversation int, message string) error { onion, _ := cp.storage.LoadProfileKeyValue(TypeAttribute, attr.PublicScope.ConstructScopedZonedPath(attr.ProfileZone.ConstructZonedPath(constants.Onion)).ToString()) // For p2p messages we store the event id of the message as the "signature" we can then look this up in the database later for acks - err := cp.storage.InsertMessage(conversationInfo.ID, 0, message, model.Attributes{constants.AttrAck: event.False, constants.AttrSentTimestamp: time.Now().Format(time.RFC3339Nano)}, ev.EventID, model.CalculateContentHash(string(onion), message)) + err := cp.storage.InsertMessage(conversationInfo.ID, 0, message, model.Attributes{constants.AttrAuthor: string(onion), constants.AttrAck: event.False, constants.AttrSentTimestamp: time.Now().Format(time.RFC3339Nano)}, ev.EventID, model.CalculateContentHash(string(onion), message)) if err != nil { return err } @@ -192,7 +193,7 @@ func (cp *cwtchPeer) SendMessage(conversation int, message string) error { } // Insert the Group Message - err = cp.storage.InsertMessage(conversationInfo.ID, 0, dm.Text, model.Attributes{constants.AttrAck: constants.False, "PreviousSignature": base64.StdEncoding.EncodeToString(dm.PreviousMessageSig), "Author": dm.Onion, constants.AttrSentTimestamp: strconv.Itoa(int(dm.Timestamp))}, base64.StdEncoding.EncodeToString(sig), model.CalculateContentHash(dm.Onion, dm.Text)) + err = cp.storage.InsertMessage(conversationInfo.ID, 0, dm.Text, model.Attributes{constants.AttrAck: constants.False, "PreviousSignature": base64.StdEncoding.EncodeToString(dm.PreviousMessageSig), constants.AttrAuthor: dm.Onion, constants.AttrSentTimestamp: time.Now().Format(time.RFC3339Nano)}, base64.StdEncoding.EncodeToString(sig), model.CalculateContentHash(dm.Onion, dm.Text)) if err == nil { ev := event.NewEvent(event.SendMessageToGroup, map[event.Field]string{event.ConversationID: strconv.Itoa(conversationInfo.ID), event.GroupID: conversationInfo.Handle, event.GroupServer: group.GroupServer, event.Ciphertext: base64.StdEncoding.EncodeToString(ct), event.Signature: base64.StdEncoding.EncodeToString(sig)}) cp.eventBus.Publish(ev) @@ -264,7 +265,9 @@ func ImportLegacyProfile(profile *model.Profile, cps *CwtchProfileStorage) Cwtch cp := new(cwtchPeer) cp.shutdown = false cp.storage = cps + cp.eventBus = event.NewEventManager() cp.queue = event.NewQueue() + cp.state = make(map[string]connections.ConnectionState) // Store all the Necessary Base Attributes In The Database cp.SetScopedZonedAttribute(attr.LocalScope, attr.ProfileZone, constants.Name, profile.Name) cp.SetScopedZonedAttribute(attr.PublicScope, attr.ProfileZone, constants.Name, profile.Name) @@ -274,7 +277,7 @@ func ImportLegacyProfile(profile *model.Profile, cps *CwtchProfileStorage) Cwtch for k, v := range profile.Attributes { parts := strings.SplitN(k, ".", 2) - if len(parts) != 2 { + if len(parts) == 2 { scope := attr.IntoScope(parts[0]) zone, path := attr.ParseZone(parts[1]) cp.SetScopedZonedAttribute(scope, zone, path, v) @@ -297,10 +300,6 @@ func ImportLegacyProfile(profile *model.Profile, cps *CwtchProfileStorage) Cwtch if err == nil { for key, value := range contact.Attributes { switch key { - case "name": - cp.SetConversationAttribute(conversationID, attr.LocalScope.ConstructScopedZonedPath(attr.ProfileZone.ConstructZonedPath(constants.Name)), value) - case "local.profile.name": - cp.SetConversationAttribute(conversationID, attr.LocalScope.ConstructScopedZonedPath(attr.ProfileZone.ConstructZonedPath(constants.Name)), value) case event.SaveHistoryKey: cp.SetConversationAttribute(conversationID, attr.LocalScope.ConstructScopedZonedPath(attr.ProfileZone.ConstructZonedPath(event.SaveHistoryKey)), value) case string(model.BundleType): @@ -311,13 +310,23 @@ func ImportLegacyProfile(profile *model.Profile, cps *CwtchProfileStorage) Cwtch // ignore case string(model.KeyTypePrivacyPass): // ignore + case lastKnownSignature: + cp.SetConversationAttribute(conversationID, attr.LocalScope.ConstructScopedZonedPath(attr.ProfileZone.ConstructZonedPath(lastReceivedSignature)), value) default: log.Errorf("could not import conversation attribute %v %v", key, value) } } + + if name, exists := contact.Attributes["local.name"]; exists { + cp.SetConversationAttribute(conversationID, attr.LocalScope.ConstructScopedZonedPath(attr.ProfileZone.ConstructZonedPath(constants.Name)), name) + } + if name, exists := contact.Attributes["peer.name"]; exists { + cp.SetConversationAttribute(conversationID, attr.PublicScope.ConstructScopedZonedPath(attr.ProfileZone.ConstructZonedPath(constants.Name)), name) + } + for _, message := range contact.Timeline.GetMessages() { // By definition anything stored in legacy timelines in acknowledged - attr := model.Attributes{constants.AttrAck: event.True, constants.AttrSentTimestamp: message.Timestamp.Format(time.RFC3339Nano)} + attr := model.Attributes{constants.AttrAuthor: message.PeerID, constants.AttrAck: event.True, constants.AttrSentTimestamp: message.Timestamp.Format(time.RFC3339Nano)} if message.Flags&0x01 == 0x01 { attr[constants.AttrRejected] = event.True } @@ -330,15 +339,15 @@ func ImportLegacyProfile(profile *model.Profile, cps *CwtchProfileStorage) Cwtch } for _, group := range profile.Groups { + group.GroupName = group.Attributes["local.name"] invite, err := group.Invite() if err == nil { // Automatically grab all the important fields... - // Including Name... conversationID, err := cp.ImportGroup(invite) if err == nil { for _, message := range group.Timeline.GetMessages() { // By definition anything stored in legacy timelines in acknowledged - attr := model.Attributes{constants.AttrAck: event.True, constants.AttrSentTimestamp: message.Timestamp.Format(time.RFC3339Nano)} + attr := model.Attributes{constants.AttrAuthor: message.PeerID, constants.AttrAck: event.True, constants.AttrSentTimestamp: message.Timestamp.Format(time.RFC3339Nano)} if message.Flags&0x01 == 0x01 { attr[constants.AttrRejected] = event.True } @@ -350,7 +359,7 @@ func ImportLegacyProfile(profile *model.Profile, cps *CwtchProfileStorage) Cwtch } } } - + cp.eventBus.Shutdown() // We disregard all events from profile... return cp } @@ -446,7 +455,7 @@ func (cp *cwtchPeer) ImportGroup(exportedInvite string) (int, error) { cp.SetConversationAttribute(groupConversationID, attr.LocalScope.ConstructScopedZonedPath(attr.LegacyGroupZone.ConstructZonedPath(constants.GroupID)), gci.GroupID) cp.SetConversationAttribute(groupConversationID, attr.LocalScope.ConstructScopedZonedPath(attr.LegacyGroupZone.ConstructZonedPath(constants.GroupServer)), gci.ServerHost) cp.SetConversationAttribute(groupConversationID, attr.LocalScope.ConstructScopedZonedPath(attr.LegacyGroupZone.ConstructZonedPath(constants.GroupKey)), base64.StdEncoding.EncodeToString(gci.SharedKey)) - cp.SetConversationAttribute(groupConversationID, attr.LocalScope.ConstructScopedZonedPath(attr.LegacyGroupZone.ConstructZonedPath(constants.Name)), gci.GroupName) + cp.SetConversationAttribute(groupConversationID, attr.LocalScope.ConstructScopedZonedPath(attr.ProfileZone.ConstructZonedPath(constants.Name)), gci.GroupName) cp.eventBus.Publish(event.NewEvent(event.NewGroup, map[event.Field]string{event.ConversationID: strconv.Itoa(groupConversationID), event.GroupServer: gci.ServerHost, event.GroupInvite: exportedInvite})) } return groupConversationID, err @@ -570,7 +579,7 @@ func (cp *cwtchPeer) StartGroup(name string, server string) (int, error) { cp.SetConversationAttribute(conversationID, attr.LocalScope.ConstructScopedZonedPath(attr.LegacyGroupZone.ConstructZonedPath(constants.GroupID)), group.GroupID) cp.SetConversationAttribute(conversationID, attr.LocalScope.ConstructScopedZonedPath(attr.LegacyGroupZone.ConstructZonedPath(constants.GroupServer)), group.GroupServer) cp.SetConversationAttribute(conversationID, attr.LocalScope.ConstructScopedZonedPath(attr.LegacyGroupZone.ConstructZonedPath(constants.GroupKey)), base64.StdEncoding.EncodeToString(group.GroupKey[:])) - cp.SetConversationAttribute(conversationID, attr.LocalScope.ConstructScopedZonedPath(attr.LegacyGroupZone.ConstructZonedPath(constants.Name)), name) + cp.SetConversationAttribute(conversationID, attr.LocalScope.ConstructScopedZonedPath(attr.ProfileZone.ConstructZonedPath(constants.Name)), name) cp.eventBus.Publish(event.NewEvent(event.GroupCreated, map[event.Field]string{ event.ConversationID: strconv.Itoa(conversationID), @@ -710,7 +719,7 @@ func (cp *cwtchPeer) SendInviteToConversation(conversationID int, inviteConversa if !ok { return errors.New("group structure is malformed - no key") } - groupName, ok := inviteConversationInfo.Attributes[attr.LocalScope.ConstructScopedZonedPath(attr.LegacyGroupZone.ConstructZonedPath(constants.Name)).ToString()] + groupName, ok := inviteConversationInfo.Attributes[attr.LocalScope.ConstructScopedZonedPath(attr.ProfileZone.ConstructZonedPath(constants.Name)).ToString()] if !ok { return errors.New("group structure is malformed - no name") } @@ -804,7 +813,7 @@ func (cp *cwtchPeer) JoinServer(onion string) error { tokenY, yExists := ci.Attributes[attr.PublicScope.ConstructScopedZonedPath(attr.ServerKeyZone.ConstructZonedPath(string(model.KeyTypePrivacyPass))).ToString()] tokenOnion, onionExists := ci.Attributes[attr.PublicScope.ConstructScopedZonedPath(attr.ServerKeyZone.ConstructZonedPath(string(model.KeyTypeTokenOnion))).ToString()] if yExists && onionExists { - signature, exists := ci.Attributes[attr.PublicScope.ConstructScopedZonedPath(attr.ServerKeyZone.ConstructZonedPath(lastKnownSignature)).ToString()] + signature, exists := ci.Attributes[attr.LocalScope.ConstructScopedZonedPath(attr.ProfileZone.ConstructZonedPath(lastReceivedSignature)).ToString()] if !exists { signature = base64.StdEncoding.EncodeToString([]byte{}) } @@ -908,7 +917,7 @@ func (cp *cwtchPeer) storeMessage(handle string, message string, sent time.Time) // Generate a random number and use it as the signature signature := event.GetRandNumber().String() - return cp.storage.InsertMessage(ci.ID, 0, message, model.Attributes{constants.AttrAck: event.True, constants.AttrSentTimestamp: sent.Format(time.RFC3339Nano)}, signature, model.CalculateContentHash(handle, message)) + return cp.storage.InsertMessage(ci.ID, 0, message, model.Attributes{constants.AttrAuthor: handle, constants.AttrAck: event.True, constants.AttrSentTimestamp: sent.Format(time.RFC3339Nano)}, signature, model.CalculateContentHash(handle, message)) } // ShareFile begins hosting the given serialized manifest @@ -1138,9 +1147,9 @@ func (cp *cwtchPeer) attemptInsertOrAcknowledgeLegacyGroupConversation(conversat } } else { cp.mutex.Lock() - cp.storage.InsertMessage(conversationID, 0, dm.Text, model.Attributes{constants.AttrAck: constants.True, "PreviousSignature": base64.StdEncoding.EncodeToString(dm.PreviousMessageSig), "Author": dm.Onion, constants.AttrSentTimestamp: strconv.Itoa(int(dm.Timestamp))}, signature, model.CalculateContentHash(dm.Onion, dm.Text)) + cp.storage.InsertMessage(conversationID, 0, dm.Text, model.Attributes{constants.AttrAck: constants.True, "PreviousSignature": base64.StdEncoding.EncodeToString(dm.PreviousMessageSig), constants.AttrAuthor: dm.Onion, constants.AttrSentTimestamp: time.Unix(int64(dm.Timestamp), 0).Format(time.RFC3339Nano)}, signature, model.CalculateContentHash(dm.Onion, dm.Text)) cp.mutex.Unlock() - cp.eventBus.Publish(event.NewEvent(event.NewMessageFromGroup, map[event.Field]string{event.ConversationID: strconv.Itoa(conversationID), event.Index: strconv.Itoa(messageID)})) + cp.eventBus.Publish(event.NewEvent(event.NewMessageFromGroup, map[event.Field]string{event.ConversationID: strconv.Itoa(conversationID), event.RemotePeer: dm.Onion, event.Index: strconv.Itoa(messageID)})) return nil } return err @@ -1204,6 +1213,12 @@ func (cp *cwtchPeer) GetChannelMessageBySignature(conversationID int, channelID return cp.storage.GetChannelMessageBySignature(conversationID, channelID, signature) } +func (cp *cwtchPeer) GetChannelMessageByContentHash(conversationID int, channelID int, contenthash string) (int, error) { + cp.mutex.Lock() + defer cp.mutex.Unlock() + return cp.storage.GetChannelMessageByContentHash(conversationID, channelID, contenthash) +} + func (cp *cwtchPeer) constructGroupFromConversation(conversationInfo *model.Conversation) (*model.Group, error) { key := conversationInfo.Attributes[attr.LocalScope.ConstructScopedZonedPath(attr.LegacyGroupZone.ConstructZonedPath(constants.GroupKey)).ToString()] groupKey, err := base64.StdEncoding.DecodeString(key) diff --git a/peer/cwtchprofilestorage.go b/peer/cwtchprofilestorage.go index 9dd436a..20ae3ae 100644 --- a/peer/cwtchprofilestorage.go +++ b/peer/cwtchprofilestorage.go @@ -43,12 +43,13 @@ type CwtchProfileStorage struct { setConversationAttributesStmt *sql.Stmt setConversationACLStmt *sql.Stmt - channelInsertStmts map[ChannelID]*sql.Stmt - channelUpdateMessageStmts map[ChannelID]*sql.Stmt - channelGetMessageStmts map[ChannelID]*sql.Stmt - channelGetMessageBySignatureStmts map[ChannelID]*sql.Stmt - channelGetCountStmts map[ChannelID]*sql.Stmt - channelGetMostRecentMessagesStmts map[ChannelID]*sql.Stmt + channelInsertStmts map[ChannelID]*sql.Stmt + channelUpdateMessageStmts map[ChannelID]*sql.Stmt + channelGetMessageStmts map[ChannelID]*sql.Stmt + channelGetMessageBySignatureStmts map[ChannelID]*sql.Stmt + channelGetCountStmts map[ChannelID]*sql.Stmt + channelGetMostRecentMessagesStmts map[ChannelID]*sql.Stmt + channelGetMessageByContentHashStmts map[ChannelID]*sql.Stmt db *sql.DB } @@ -87,7 +88,7 @@ const getMessageFromConversationSQLStmt = `select Body, Attributes from channel_ const getMessageBySignatureFromConversationSQLStmt = `select ID from channel_%d_%d_chat where Signature=(?);` // getMessageByContentHashFromConversationSQLStmt is a template for selecting conversation messages by content hash -const getMessageByContentHashFromConversationSQLStmt = `select ID from channel_%d_%d_chat where ContentHash=(?);` +const getMessageByContentHashFromConversationSQLStmt = `select ID from channel_%d_%d_chat where ContentHash=(?) order by ID desc limit 1;` // getMessageCountFromConversationSQLStmt is a template for fetching the count of a messages in a conversation channel const getMessageCountFromConversationSQLStmt = `select count(*) from channel_%d_%d_chat;` @@ -164,22 +165,23 @@ func NewCwtchProfileStorage(db *sql.DB) (*CwtchProfileStorage, error) { } return &CwtchProfileStorage{db: db, - insertProfileKeyValueStmt: insertProfileKeyValueStmt, - selectProfileKeyValueStmt: selectProfileKeyStmt, - fetchAllConversationsStmt: fetchAllConversationsStmt, - insertConversationStmt: insertConversationStmt, - selectConversationStmt: selectConversationStmt, - selectConversationByHandleStmt: selectConversationByHandleStmt, - acceptConversationStmt: acceptConversationStmt, - deleteConversationStmt: deleteConversationStmt, - setConversationAttributesStmt: setConversationAttributesStmt, - setConversationACLStmt: setConversationACLStmt, - channelInsertStmts: map[ChannelID]*sql.Stmt{}, - channelUpdateMessageStmts: map[ChannelID]*sql.Stmt{}, - channelGetMessageStmts: map[ChannelID]*sql.Stmt{}, - channelGetMessageBySignatureStmts: map[ChannelID]*sql.Stmt{}, - channelGetMostRecentMessagesStmts: map[ChannelID]*sql.Stmt{}, - channelGetCountStmts: map[ChannelID]*sql.Stmt{}}, + insertProfileKeyValueStmt: insertProfileKeyValueStmt, + selectProfileKeyValueStmt: selectProfileKeyStmt, + fetchAllConversationsStmt: fetchAllConversationsStmt, + insertConversationStmt: insertConversationStmt, + selectConversationStmt: selectConversationStmt, + selectConversationByHandleStmt: selectConversationByHandleStmt, + acceptConversationStmt: acceptConversationStmt, + deleteConversationStmt: deleteConversationStmt, + setConversationAttributesStmt: setConversationAttributesStmt, + setConversationACLStmt: setConversationACLStmt, + channelInsertStmts: map[ChannelID]*sql.Stmt{}, + channelUpdateMessageStmts: map[ChannelID]*sql.Stmt{}, + channelGetMessageStmts: map[ChannelID]*sql.Stmt{}, + channelGetMessageBySignatureStmts: map[ChannelID]*sql.Stmt{}, + channelGetMessageByContentHashStmts: map[ChannelID]*sql.Stmt{}, + channelGetMostRecentMessagesStmts: map[ChannelID]*sql.Stmt{}, + channelGetCountStmts: map[ChannelID]*sql.Stmt{}}, nil } @@ -423,7 +425,6 @@ func (cps *CwtchProfileStorage) InsertMessage(conversation int, channel int, bod return err } - log.Infof("inserted message with signature: %v", signature) return nil } @@ -489,6 +490,43 @@ func (cps *CwtchProfileStorage) GetChannelMessageBySignature(conversation int, c return id, nil } +// GetChannelMessageByContentHash looks up a conversation message by hash instead of identifier. +func (cps *CwtchProfileStorage) GetChannelMessageByContentHash(conversation int, channel int, hash string) (int, error) { + channelID := ChannelID{Conversation: conversation, Channel: channel} + + _, exists := cps.channelGetMessageByContentHashStmts[channelID] + if !exists { + conversationStmt, err := cps.db.Prepare(fmt.Sprintf(getMessageByContentHashFromConversationSQLStmt, conversation, channel)) + if err != nil { + log.Errorf("error executing transaction: %v", err) + return -1, err + } + cps.channelGetMessageByContentHashStmts[channelID] = conversationStmt + } + + rows, err := cps.channelGetMessageByContentHashStmts[channelID].Query(hash) + if err != nil { + log.Errorf("error executing query: %v", err) + return -1, err + } + + result := rows.Next() + + if !result { + return -1, errors.New("no result found") + } + + var id int + err = rows.Scan(&id) + if err != nil { + log.Errorf("error fetching rows: %v", err) + rows.Close() + return -1, err + } + rows.Close() + return id, nil +} + // GetChannelMessage looks up a channel message by conversation, channel and message id. On success it // returns the message body and the attributes associated with the message. Otherwise an error is returned. func (cps *CwtchProfileStorage) GetChannelMessage(conversation int, channel int, messageID int) (string, model.Attributes, error) { diff --git a/peer/profile_interface.go b/peer/profile_interface.go index 81070ee..eefd542 100644 --- a/peer/profile_interface.go +++ b/peer/profile_interface.go @@ -114,6 +114,7 @@ type CwtchPeer interface { // New Unified Conversation Channel Interfaces GetChannelMessage(conversation int, channel int, id int) (string, model.Attributes, error) GetChannelMessageCount(conversation int, channel int) (int, error) + GetChannelMessageByContentHash(conversation int, channel int, contenthash string) (int, error) GetMostRecentMessages(conversation int, channel int, offset int, limit int) ([]model.ConversationMessage, error) ShareFile(fileKey string, serializedManifest string) diff --git a/peer/storage.go b/peer/storage.go index c84a321..a273ba0 100644 --- a/peer/storage.go +++ b/peer/storage.go @@ -3,6 +3,7 @@ package peer import ( "crypto/rand" "database/sql" + "errors" "fmt" "git.openprivacy.ca/openprivacy/log" "golang.org/x/crypto/pbkdf2" @@ -63,7 +64,7 @@ func initV2Directory(directory, password string) ([32]byte, [128]byte, error) { return key, salt, nil } -func openEncryptedDatabase(profileDirectory string, password string) (*sql.DB, error) { +func openEncryptedDatabase(profileDirectory string, password string, createIfNotExists bool) (*sql.DB, error) { salt, err := ioutil.ReadFile(path.Join(profileDirectory, saltFile)) if err != nil { return nil, err @@ -71,6 +72,13 @@ func openEncryptedDatabase(profileDirectory string, password string) (*sql.DB, e key := createKey(password, salt) dbPath := filepath.Join(profileDirectory, "db") + + if !createIfNotExists { + if _, err := os.Stat(dbPath); errors.Is(err, os.ErrNotExist) { + return nil, err + } + } + dbname := fmt.Sprintf("%v?_pragma_key=x'%x'&_pragma_cipher_page_size=8192", dbPath, key) db, err := sql.Open("sqlite3", dbname) if err != nil { @@ -89,7 +97,7 @@ func CreateEncryptedStorePeer(profileDirectory string, name string, password str } log.Debugf("Opening Encrypted Database") - db, err := openEncryptedDatabase(profileDirectory, password) + db, err := openEncryptedDatabase(profileDirectory, password, true) if db == nil || err != nil { return nil, fmt.Errorf("unable to open encrypted database: error: %v", err) } @@ -115,14 +123,9 @@ func CreateEncryptedStorePeer(profileDirectory string, name string, password str // CreateEncryptedStore creates a encrypted datastore func CreateEncryptedStore(profileDirectory string, password string) (*CwtchProfileStorage, error) { - log.Debugf("Initializing Encrypted Storage Directory") - _, _, err := initV2Directory(profileDirectory, password) - if err != nil { - return nil, err - } - log.Debugf("Opening Encrypted Database") - db, err := openEncryptedDatabase(profileDirectory, password) + log.Debugf("Creating Encrypted Database") + db, err := openEncryptedDatabase(profileDirectory, password, true) if db == nil || err != nil { return nil, fmt.Errorf("unable to open encrypted database: error: %v", err) } @@ -148,8 +151,8 @@ func CreateEncryptedStore(profileDirectory string, password string) (*CwtchProfi // FromEncryptedDatabase constructs a Cwtch Profile from an existing Encrypted Database func FromEncryptedDatabase(profileDirectory string, password string) (CwtchPeer, error) { - log.Debugf("Loading Encrypted Profile") - db, err := openEncryptedDatabase(profileDirectory, password) + log.Infof("Loading Encrypted Profile: %v", profileDirectory) + db, err := openEncryptedDatabase(profileDirectory, password, false) if db == nil || err != nil { return nil, fmt.Errorf("unable to open encrypted database: error: %v", err) } diff --git a/storage/profile_store.go b/storage/profile_store.go index 89c28cd..8c08943 100644 --- a/storage/profile_store.go +++ b/storage/profile_store.go @@ -21,8 +21,8 @@ func CreateProfileWriterStore(eventManager event.Manager, directory, password st // LoadProfileWriterStore loads a profile store from filestore listening for events and saving them // directory should be $appDir/profiles/$rand -func LoadProfileWriterStore(eventManager event.Manager, directory, password string) (ProfileStore, error) { - return v1.LoadProfileWriterStore(eventManager, directory, password) +func LoadProfileWriterStore(directory, password string) (ProfileStore, error) { + return v1.LoadProfileWriterStore(directory, password) } // ReadProfile reads a profile from storage and returns the profile diff --git a/storage/v1/profile_store.go b/storage/v1/profile_store.go index 9488ea8..88078d5 100644 --- a/storage/v1/profile_store.go +++ b/storage/v1/profile_store.go @@ -68,7 +68,7 @@ func CreateProfileWriterStore(eventManager event.Manager, directory, password st // LoadProfileWriterStore loads a profile store from filestore listening for events and saving them // directory should be $appDir/profiles/$rand -func LoadProfileWriterStore(eventManager event.Manager, directory, password string) (*ProfileStoreV1, error) { +func LoadProfileWriterStore(directory, password string) (*ProfileStoreV1, error) { salt, err := ioutil.ReadFile(path.Join(directory, saltFile)) if err != nil { return nil, err