Implement local-first remote sync flow
This commit is contained in:
+40
-3
@@ -3,6 +3,7 @@ package vault
|
||||
import (
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
@@ -23,9 +24,10 @@ type KDBXConfig struct {
|
||||
var ErrInvalidMasterKey = errors.New("invalid master key")
|
||||
|
||||
const (
|
||||
templatesRoot = "Templates"
|
||||
recycleBinRoot = "Recycle Bin"
|
||||
keepassGOIDField = "KeePassGO-ID"
|
||||
templatesRoot = "Templates"
|
||||
recycleBinRoot = "Recycle Bin"
|
||||
keepassGOIDField = "KeePassGO-ID"
|
||||
remoteProfilesKey = "keepassgo.remoteProfiles"
|
||||
)
|
||||
|
||||
func LoadKDBX(r io.Reader, password string) (Model, error) {
|
||||
@@ -49,6 +51,7 @@ func SaveKDBXWithConfigAndKey(wr io.Writer, model Model, key MasterKey, config *
|
||||
db := gokeepasslib.NewDatabase(gokeepasslib.WithDatabaseKDBXVersion4())
|
||||
db.Credentials = credentials
|
||||
db.Content.Meta = gokeepasslib.NewMetaData()
|
||||
db.Content.Meta.CustomData = customDataForModel(model)
|
||||
db.Content.Root = &gokeepasslib.RootData{}
|
||||
if config != nil && config.Header != nil {
|
||||
db.Header = cloneHeader(config.Header)
|
||||
@@ -325,6 +328,7 @@ func LoadKDBXWithConfig(r io.Reader, key MasterKey) (Model, *KDBXConfig, error)
|
||||
for _, group := range db.Content.Root.Groups {
|
||||
appendGroupEntries(&model, db, group, nil)
|
||||
}
|
||||
model.RemoteProfiles = remoteProfilesFromMeta(db.Content.Meta)
|
||||
|
||||
return model, &KDBXConfig{
|
||||
Header: cloneHeader(db.Header),
|
||||
@@ -332,6 +336,39 @@ func LoadKDBXWithConfig(r io.Reader, key MasterKey) (Model, *KDBXConfig, error)
|
||||
}, nil
|
||||
}
|
||||
|
||||
func customDataForModel(model Model) []gokeepasslib.CustomData {
|
||||
if len(model.RemoteProfiles) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
content, err := json.Marshal(model.RemoteProfiles)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return []gokeepasslib.CustomData{{
|
||||
Key: remoteProfilesKey,
|
||||
Value: string(content),
|
||||
}}
|
||||
}
|
||||
|
||||
func remoteProfilesFromMeta(meta *gokeepasslib.MetaData) []RemoteProfile {
|
||||
if meta == nil {
|
||||
return nil
|
||||
}
|
||||
for _, item := range meta.CustomData {
|
||||
if item.Key != remoteProfilesKey {
|
||||
continue
|
||||
}
|
||||
var profiles []RemoteProfile
|
||||
if err := json.Unmarshal([]byte(item.Value), &profiles); err != nil {
|
||||
return nil
|
||||
}
|
||||
return profiles
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func newCredentials(key MasterKey) (*gokeepasslib.DBCredentials, error) {
|
||||
switch {
|
||||
case key.Password != "" && len(key.KeyFileData) > 0:
|
||||
|
||||
Reference in New Issue
Block a user