Open remote vaults from vault bindings
This commit is contained in:
@@ -834,6 +834,25 @@ func (s *State) OpenRemoteVault(client webdav.Client, path string, key vault.Mas
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *State) OpenBoundRemoteVault(binding RemoteBinding, key vault.MasterKey) error {
|
||||||
|
model, err := s.currentModel()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
resolved, err := binding.Resolve(model)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
client := webdav.Client{
|
||||||
|
BaseURL: resolved.Profile.BaseURL,
|
||||||
|
Username: resolved.Credentials.Username,
|
||||||
|
Password: resolved.Credentials.Password,
|
||||||
|
}
|
||||||
|
return s.OpenRemoteVault(client, resolved.Profile.Path, key)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *State) CreateGroup(name string) error {
|
func (s *State) CreateGroup(name string) error {
|
||||||
session, ok := s.Session.(MutableSession)
|
session, ok := s.Session.(MutableSession)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|||||||
+86
-2
@@ -964,6 +964,87 @@ func TestOpenRemoteVaultResetsSelectionPathAndDirtyState(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestOpenBoundRemoteVaultResolvesClientFromVaultBinding(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
sess := &lifecycleStubSession{
|
||||||
|
model: vault.Model{
|
||||||
|
Entries: []vault.Entry{
|
||||||
|
{
|
||||||
|
ID: "remote-creds-1",
|
||||||
|
Title: "WebDAV Sign-In",
|
||||||
|
Username: "tjulian",
|
||||||
|
Password: "token-1",
|
||||||
|
Path: []string{"Crew", "Internet"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
RemoteProfiles: []vault.RemoteProfile{
|
||||||
|
{
|
||||||
|
ID: "family-webdav",
|
||||||
|
Name: "Family Vault",
|
||||||
|
Backend: vault.RemoteBackendWebDAV,
|
||||||
|
BaseURL: "https://dav.example.invalid/remote.php/dav",
|
||||||
|
Path: "files/family/keepass.kdbx",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
state := State{
|
||||||
|
Session: sess,
|
||||||
|
CurrentPath: []string{"Root", "Internet"},
|
||||||
|
SelectedEntryID: "vault-console",
|
||||||
|
Dirty: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
err := state.OpenBoundRemoteVault(RemoteBinding{
|
||||||
|
LocalVaultPath: "/tmp/family.kdbx",
|
||||||
|
RemoteProfileID: "family-webdav",
|
||||||
|
CredentialEntryID: "remote-creds-1",
|
||||||
|
SyncMode: SyncModeAutomaticOnOpenSave,
|
||||||
|
}, vault.MasterKey{Password: "correct horse battery staple"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("OpenBoundRemoteVault() error = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if got := sess.remoteClient.BaseURL; got != "https://dav.example.invalid/remote.php/dav" {
|
||||||
|
t.Fatalf("remote client base URL = %q, want remote.php/dav URL", got)
|
||||||
|
}
|
||||||
|
if got := sess.remoteClient.Username; got != "tjulian" {
|
||||||
|
t.Fatalf("remote client username = %q, want tjulian", got)
|
||||||
|
}
|
||||||
|
if got := sess.remoteClient.Password; got != "token-1" {
|
||||||
|
t.Fatalf("remote client password = %q, want token-1", got)
|
||||||
|
}
|
||||||
|
if got := sess.remotePath; got != "files/family/keepass.kdbx" {
|
||||||
|
t.Fatalf("remotePath = %q, want files/family/keepass.kdbx", got)
|
||||||
|
}
|
||||||
|
if len(state.CurrentPath) != 0 {
|
||||||
|
t.Fatalf("CurrentPath = %v, want empty", state.CurrentPath)
|
||||||
|
}
|
||||||
|
if state.SelectedEntryID != "" {
|
||||||
|
t.Fatalf("SelectedEntryID = %q, want empty", state.SelectedEntryID)
|
||||||
|
}
|
||||||
|
if state.Dirty {
|
||||||
|
t.Fatal("Dirty = true, want false after bound remote open")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestOpenBoundRemoteVaultReturnsResolutionErrors(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
sess := &lifecycleStubSession{model: vault.Model{}}
|
||||||
|
state := State{Session: sess}
|
||||||
|
|
||||||
|
err := state.OpenBoundRemoteVault(RemoteBinding{
|
||||||
|
LocalVaultPath: "/tmp/family.kdbx",
|
||||||
|
RemoteProfileID: "missing-profile",
|
||||||
|
CredentialEntryID: "remote-creds-1",
|
||||||
|
}, vault.MasterKey{Password: "correct horse battery staple"})
|
||||||
|
if !errors.Is(err, vault.ErrRemoteProfileNotFound) {
|
||||||
|
t.Fatalf("OpenBoundRemoteVault() error = %v, want ErrRemoteProfileNotFound", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestLockClearsSelectionAndMakesVaultUnavailable(t *testing.T) {
|
func TestLockClearsSelectionAndMakesVaultUnavailable(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
@@ -1554,14 +1635,16 @@ func (s *saveableStubSession) Save() error {
|
|||||||
|
|
||||||
type lifecycleStubSession struct {
|
type lifecycleStubSession struct {
|
||||||
createCalls int
|
createCalls int
|
||||||
|
model vault.Model
|
||||||
openPath string
|
openPath string
|
||||||
saveAsPath string
|
saveAsPath string
|
||||||
|
remoteClient webdav.Client
|
||||||
remotePath string
|
remotePath string
|
||||||
changedKey vault.MasterKey
|
changedKey vault.MasterKey
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *lifecycleStubSession) Current() (vault.Model, error) {
|
func (s *lifecycleStubSession) Current() (vault.Model, error) {
|
||||||
return vault.Model{}, nil
|
return s.model, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *lifecycleStubSession) Create(_ vault.Model, _ vault.MasterKey) error {
|
func (s *lifecycleStubSession) Create(_ vault.Model, _ vault.MasterKey) error {
|
||||||
@@ -1579,7 +1662,8 @@ func (s *lifecycleStubSession) SaveAs(path string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *lifecycleStubSession) OpenRemote(_ webdav.Client, path string, _ vault.MasterKey) error {
|
func (s *lifecycleStubSession) OpenRemote(client webdav.Client, path string, _ vault.MasterKey) error {
|
||||||
|
s.remoteClient = client
|
||||||
s.remotePath = path
|
s.remotePath = path
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user