Avoid blocking UI during vault open and unlock

This commit is contained in:
Joe Julian
2026-04-01 16:54:16 -07:00
parent 4f2bb3d158
commit 80737869ea
4 changed files with 513 additions and 49 deletions
+127 -40
View File
@@ -32,6 +32,33 @@ type Manager struct {
remoteVersion webdav.Version
}
type PreparedLocalOpen struct {
Model vault.Model
Config *vault.KDBXConfig
Path string
Key vault.MasterKey
Encoded []byte
VaultRoot string
}
type PreparedRemoteOpen struct {
Model vault.Model
Config *vault.KDBXConfig
Client webdav.Client
Path string
Key vault.MasterKey
Encoded []byte
VaultRoot string
RemoteVersion webdav.Version
}
type PreparedUnlock struct {
Model vault.Model
Config *vault.KDBXConfig
Key vault.MasterKey
VaultRoot string
}
func (m *Manager) SecuritySettings() vault.SecuritySettings {
return vault.DetectSecuritySettings(m.config)
}
@@ -65,6 +92,10 @@ func (m *Manager) HasVault() bool {
return len(m.encoded) > 0 || m.path != "" || m.remotePath != ""
}
func (m *Manager) EncodedBytes() []byte {
return append([]byte(nil), m.encoded...)
}
func (m *Manager) IsLocked() bool {
return m.locked
}
@@ -74,23 +105,11 @@ func (m *Manager) IsRemote() bool {
}
func (m *Manager) Open(path string, key vault.MasterKey) error {
content, err := os.ReadFile(path)
prepared, err := PrepareLocalOpen(path, key)
if err != nil {
return fmt.Errorf("read %s: %w", path, err)
return err
}
model, config, err := vault.LoadKDBXWithConfig(bytes.NewReader(content), key)
if err != nil {
return fmt.Errorf("open %s: %w", path, err)
}
m.model = model
m.config = config
m.path = path
m.key = key
m.vaultRoot = detectSingleVaultRoot(model)
m.encoded = content
m.locked = false
m.ApplyPreparedLocalOpen(prepared)
return nil
}
@@ -107,25 +126,11 @@ func (m *Manager) Save() error {
}
func (m *Manager) OpenRemote(client webdav.Client, path string, key vault.MasterKey) error {
content, version, err := client.Open(path)
prepared, err := PrepareRemoteOpen(client, path, key)
if err != nil {
return fmt.Errorf("open remote %s: %w", path, err)
return err
}
model, config, err := vault.LoadKDBXWithConfig(bytes.NewReader(content), key)
if err != nil {
return fmt.Errorf("decode remote %s: %w", path, err)
}
m.model = model
m.config = config
m.key = key
m.vaultRoot = detectSingleVaultRoot(model)
m.encoded = content
m.locked = false
m.remoteClient = &client
m.remotePath = path
m.remoteVersion = version
m.ApplyPreparedRemoteOpen(prepared)
return nil
}
@@ -265,19 +270,101 @@ func (m *Manager) Lock() error {
}
func (m *Manager) Unlock(key vault.MasterKey) error {
model, config, err := vault.LoadKDBXWithConfig(bytes.NewReader(m.encoded), key)
prepared, err := PrepareUnlock(m.encoded, key)
if err != nil {
return fmt.Errorf("unlock vault: %w", err)
return err
}
m.model = model
m.config = config
m.key = key
m.vaultRoot = detectSingleVaultRoot(model)
m.locked = false
m.ApplyPreparedUnlock(prepared)
return nil
}
func PrepareLocalOpen(path string, key vault.MasterKey) (PreparedLocalOpen, error) {
content, err := os.ReadFile(path)
if err != nil {
return PreparedLocalOpen{}, fmt.Errorf("read %s: %w", path, err)
}
model, config, err := vault.LoadKDBXWithConfig(bytes.NewReader(content), key)
if err != nil {
return PreparedLocalOpen{}, fmt.Errorf("open %s: %w", path, err)
}
return PreparedLocalOpen{
Model: model,
Config: config,
Path: path,
Key: key,
Encoded: content,
VaultRoot: detectSingleVaultRoot(model),
}, nil
}
func PrepareRemoteOpen(client webdav.Client, path string, key vault.MasterKey) (PreparedRemoteOpen, error) {
content, version, err := client.Open(path)
if err != nil {
return PreparedRemoteOpen{}, fmt.Errorf("open remote %s: %w", path, err)
}
model, config, err := vault.LoadKDBXWithConfig(bytes.NewReader(content), key)
if err != nil {
return PreparedRemoteOpen{}, fmt.Errorf("decode remote %s: %w", path, err)
}
return PreparedRemoteOpen{
Model: model,
Config: config,
Client: client,
Path: path,
Key: key,
Encoded: content,
VaultRoot: detectSingleVaultRoot(model),
RemoteVersion: version,
}, nil
}
func PrepareUnlock(encoded []byte, key vault.MasterKey) (PreparedUnlock, error) {
model, config, err := vault.LoadKDBXWithConfig(bytes.NewReader(encoded), key)
if err != nil {
return PreparedUnlock{}, fmt.Errorf("unlock vault: %w", err)
}
return PreparedUnlock{
Model: model,
Config: config,
Key: key,
VaultRoot: detectSingleVaultRoot(model),
}, nil
}
func (m *Manager) ApplyPreparedLocalOpen(prepared PreparedLocalOpen) {
m.model = prepared.Model
m.config = prepared.Config
m.path = prepared.Path
m.key = prepared.Key
m.vaultRoot = prepared.VaultRoot
m.encoded = prepared.Encoded
m.locked = false
m.remoteClient = nil
m.remotePath = ""
m.remoteVersion = webdav.Version{}
}
func (m *Manager) ApplyPreparedRemoteOpen(prepared PreparedRemoteOpen) {
m.model = prepared.Model
m.config = prepared.Config
m.key = prepared.Key
m.vaultRoot = prepared.VaultRoot
m.encoded = prepared.Encoded
m.locked = false
m.remoteClient = &prepared.Client
m.remotePath = prepared.Path
m.remoteVersion = prepared.RemoteVersion
m.path = ""
}
func (m *Manager) ApplyPreparedUnlock(prepared PreparedUnlock) {
m.model = prepared.Model
m.config = prepared.Config
m.key = prepared.Key
m.vaultRoot = prepared.VaultRoot
m.locked = false
}
func (m *Manager) ChangeMasterKey(key vault.MasterKey) error {
var (
model vault.Model