Materialize local cache on first remote open
This commit is contained in:
+191
-6
@@ -262,7 +262,12 @@ func TestUIClearingSearchResetsToCurrentSectionListing(t *testing.T) {
|
||||
func TestUIRunBackgroundActionIgnoresDuplicateWhileLoading(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
u := newUIWithSession("desktop", &session.Manager{})
|
||||
u := newUIWithState("desktop", &session.Manager{}, statePaths{
|
||||
DefaultSaveAsPath: filepath.Join(t.TempDir(), "default-save-path.kdbx"),
|
||||
RecentVaultsPath: filepath.Join(t.TempDir(), "recent-vaults.json"),
|
||||
RecentRemotesPath: filepath.Join(t.TempDir(), "recent-remotes.json"),
|
||||
UIPreferencesPath: filepath.Join(t.TempDir(), "ui-preferences.json"),
|
||||
})
|
||||
started := make(chan struct{})
|
||||
release := make(chan struct{})
|
||||
runs := 0
|
||||
@@ -298,7 +303,12 @@ func TestUIRunBackgroundActionIgnoresDuplicateWhileLoading(t *testing.T) {
|
||||
func TestUICancelLifecycleBusyStateIgnoresLateResultAndKeepsRetryAvailable(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
u := newUIWithSession("desktop", &session.Manager{})
|
||||
u := newUIWithState("desktop", &session.Manager{}, statePaths{
|
||||
DefaultSaveAsPath: filepath.Join(t.TempDir(), "default-save-path.kdbx"),
|
||||
RecentVaultsPath: filepath.Join(t.TempDir(), "recent-vaults.json"),
|
||||
RecentRemotesPath: filepath.Join(t.TempDir(), "recent-remotes.json"),
|
||||
UIPreferencesPath: filepath.Join(t.TempDir(), "ui-preferences.json"),
|
||||
})
|
||||
u.vaultPath.SetText("/tmp/example.kdbx")
|
||||
u.lastLifecycleAction = "open vault"
|
||||
|
||||
@@ -1191,7 +1201,12 @@ func TestUISaveSecuritySettingsUpdatesExistingVault(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
manager := &session.Manager{}
|
||||
u := newUIWithSession("desktop", manager)
|
||||
u := newUIWithState("desktop", manager, statePaths{
|
||||
DefaultSaveAsPath: filepath.Join(t.TempDir(), "default-save-path.kdbx"),
|
||||
RecentVaultsPath: filepath.Join(t.TempDir(), "recent-vaults.json"),
|
||||
RecentRemotesPath: filepath.Join(t.TempDir(), "recent-remotes.json"),
|
||||
UIPreferencesPath: filepath.Join(t.TempDir(), "ui-preferences.json"),
|
||||
})
|
||||
u.masterPassword.SetText("correct horse battery staple")
|
||||
if err := u.createVaultAction(); err != nil {
|
||||
t.Fatalf("createVaultAction() error = %v", err)
|
||||
@@ -1263,7 +1278,12 @@ func TestUISaveSettingsPersistsUIPreferences(t *testing.T) {
|
||||
func TestUILockAndUnlockClearMasterPasswordField(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
u := newUIWithSession("desktop", &session.Manager{})
|
||||
u := newUIWithState("desktop", &session.Manager{}, statePaths{
|
||||
DefaultSaveAsPath: filepath.Join(t.TempDir(), "default-save-path.kdbx"),
|
||||
RecentVaultsPath: filepath.Join(t.TempDir(), "recent-vaults.json"),
|
||||
RecentRemotesPath: filepath.Join(t.TempDir(), "recent-remotes.json"),
|
||||
UIPreferencesPath: filepath.Join(t.TempDir(), "ui-preferences.json"),
|
||||
})
|
||||
u.masterPassword.SetText("correct horse battery staple")
|
||||
if err := u.createVaultAction(); err != nil {
|
||||
t.Fatalf("createVaultAction() error = %v", err)
|
||||
@@ -1621,7 +1641,12 @@ func TestUIStartOpenRemoteActionAppliesResultOnMainThread(t *testing.T) {
|
||||
defer server.Close()
|
||||
|
||||
manager := &session.Manager{}
|
||||
u := newUIWithSession("desktop", manager)
|
||||
u := newUIWithState("desktop", manager, statePaths{
|
||||
DefaultSaveAsPath: filepath.Join(t.TempDir(), "default-save-path.kdbx"),
|
||||
RecentVaultsPath: filepath.Join(t.TempDir(), "recent-vaults.json"),
|
||||
RecentRemotesPath: filepath.Join(t.TempDir(), "recent-remotes.json"),
|
||||
UIPreferencesPath: filepath.Join(t.TempDir(), "ui-preferences.json"),
|
||||
})
|
||||
u.masterPassword.SetText(key.Password)
|
||||
u.remoteBaseURL.SetText(server.URL)
|
||||
u.remotePath.SetText("vaults/main.kdbx")
|
||||
@@ -1659,7 +1684,12 @@ func TestUIOpenRemoteReportsTransportFailure(t *testing.T) {
|
||||
url := server.URL
|
||||
server.Close()
|
||||
|
||||
u := newUIWithSession("desktop", &session.Manager{})
|
||||
u := newUIWithState("desktop", &session.Manager{}, statePaths{
|
||||
DefaultSaveAsPath: filepath.Join(t.TempDir(), "default-save-path.kdbx"),
|
||||
RecentVaultsPath: filepath.Join(t.TempDir(), "recent-vaults.json"),
|
||||
RecentRemotesPath: filepath.Join(t.TempDir(), "recent-remotes.json"),
|
||||
UIPreferencesPath: filepath.Join(t.TempDir(), "ui-preferences.json"),
|
||||
})
|
||||
u.masterPassword.SetText("correct horse battery staple")
|
||||
u.remoteBaseURL.SetText(url)
|
||||
u.remotePath.SetText("vaults/main.kdbx")
|
||||
@@ -5331,6 +5361,161 @@ func TestUIOpenRemoteVaultRestoresLastOpenedGroupForThatConnection(t *testing.T)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUIOpenRemoteActionMaterializesLocalCacheAndBinding(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
dir := t.TempDir()
|
||||
cachePath := filepath.Join(dir, "remote-cache.kdbx")
|
||||
paths := statePaths{
|
||||
DefaultSaveAsPath: cachePath,
|
||||
RecentVaultsPath: filepath.Join(dir, "recent-vaults.json"),
|
||||
RecentRemotesPath: filepath.Join(dir, "recent-remotes.json"),
|
||||
UIPreferencesPath: filepath.Join(dir, "ui-prefs.json"),
|
||||
}
|
||||
key := vault.MasterKey{Password: "correct horse battery staple"}
|
||||
|
||||
var encoded bytes.Buffer
|
||||
if err := vault.SaveKDBXWithKey(&encoded, vault.Model{
|
||||
Entries: []vault.Entry{
|
||||
{ID: "entry-1", Title: "Vault Console", Path: []string{"Root", "Internet"}},
|
||||
},
|
||||
}, key); err != nil {
|
||||
t.Fatalf("SaveKDBXWithKey() error = %v", err)
|
||||
}
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
username, password, ok := r.BasicAuth()
|
||||
if !ok || username != "tjulian" || password != "token-1" {
|
||||
t.Fatalf("BasicAuth() = (%q, %q, %t), want (tjulian, token-1, true)", username, password, ok)
|
||||
}
|
||||
if r.Method != http.MethodGet {
|
||||
t.Fatalf("method = %s, want GET", r.Method)
|
||||
}
|
||||
w.Header().Set("ETag", "\"v1\"")
|
||||
_, _ = w.Write(encoded.Bytes())
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
u := newUIWithState("desktop", &session.Manager{}, paths)
|
||||
u.lifecycleMode = "remote"
|
||||
u.masterPassword.SetText(key.Password)
|
||||
u.remoteBaseURL.SetText(server.URL)
|
||||
u.remotePath.SetText("vault.kdbx")
|
||||
u.remoteUsername.SetText("tjulian")
|
||||
u.remotePassword.SetText("token-1")
|
||||
|
||||
if err := u.openRemoteAction(); err != nil {
|
||||
t.Fatalf("openRemoteAction() error = %v", err)
|
||||
}
|
||||
|
||||
if got := u.vaultPath.Text(); got != cachePath {
|
||||
t.Fatalf("vaultPath = %q, want %q", got, cachePath)
|
||||
}
|
||||
if _, err := os.Stat(cachePath); err != nil {
|
||||
t.Fatalf("Stat(cachePath) error = %v", err)
|
||||
}
|
||||
if got := len(u.recentRemotes); got != 1 {
|
||||
t.Fatalf("len(recentRemotes) = %d, want 1", got)
|
||||
}
|
||||
record := u.recentRemotes[0]
|
||||
if record.LocalVaultPath != cachePath {
|
||||
t.Fatalf("recentRemotes[0].LocalVaultPath = %q, want %q", record.LocalVaultPath, cachePath)
|
||||
}
|
||||
if record.RemoteProfileID == "" || record.CredentialEntryID == "" {
|
||||
t.Fatalf("recentRemotes[0] = %#v, want binding ids populated", record)
|
||||
}
|
||||
|
||||
var reopened session.Manager
|
||||
if err := reopened.Open(cachePath, key); err != nil {
|
||||
t.Fatalf("Open(cachePath) error = %v", err)
|
||||
}
|
||||
model, err := reopened.Current()
|
||||
if err != nil {
|
||||
t.Fatalf("Current() error = %v", err)
|
||||
}
|
||||
if got := len(model.RemoteProfiles); got != 1 {
|
||||
t.Fatalf("len(RemoteProfiles) = %d, want 1", got)
|
||||
}
|
||||
if got := model.RemoteProfiles[0].BaseURL; got != server.URL {
|
||||
t.Fatalf("RemoteProfiles[0].BaseURL = %q, want %q", got, server.URL)
|
||||
}
|
||||
entry, err := model.EntryByID(record.CredentialEntryID)
|
||||
if err != nil {
|
||||
t.Fatalf("EntryByID(%q) error = %v", record.CredentialEntryID, err)
|
||||
}
|
||||
if entry.Username != "tjulian" || entry.Password != "token-1" {
|
||||
t.Fatalf("credential entry = %#v, want tjulian/token-1", entry)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUIStartOpenRemoteActionMaterializesLocalCacheAndBinding(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
dir := t.TempDir()
|
||||
cachePath := filepath.Join(dir, "remote-cache.kdbx")
|
||||
paths := statePaths{
|
||||
DefaultSaveAsPath: cachePath,
|
||||
RecentVaultsPath: filepath.Join(dir, "recent-vaults.json"),
|
||||
RecentRemotesPath: filepath.Join(dir, "recent-remotes.json"),
|
||||
UIPreferencesPath: filepath.Join(dir, "ui-prefs.json"),
|
||||
}
|
||||
key := vault.MasterKey{Password: "correct horse battery staple"}
|
||||
|
||||
var encoded bytes.Buffer
|
||||
if err := vault.SaveKDBXWithKey(&encoded, vault.Model{
|
||||
Entries: []vault.Entry{
|
||||
{ID: "entry-1", Title: "Vault Console", Path: []string{"Root", "Internet"}},
|
||||
},
|
||||
}, key); err != nil {
|
||||
t.Fatalf("SaveKDBXWithKey() error = %v", err)
|
||||
}
|
||||
|
||||
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
username, password, ok := r.BasicAuth()
|
||||
if !ok || username != "tjulian" || password != "token-1" {
|
||||
t.Fatalf("BasicAuth() = (%q, %q, %t), want (tjulian, token-1, true)", username, password, ok)
|
||||
}
|
||||
if r.Method != http.MethodGet {
|
||||
t.Fatalf("method = %s, want GET", r.Method)
|
||||
}
|
||||
w.Header().Set("ETag", "\"v1\"")
|
||||
_, _ = w.Write(encoded.Bytes())
|
||||
}))
|
||||
defer server.Close()
|
||||
|
||||
u := newUIWithState("desktop", &session.Manager{}, paths)
|
||||
u.lifecycleMode = "remote"
|
||||
u.masterPassword.SetText(key.Password)
|
||||
u.remoteBaseURL.SetText(server.URL)
|
||||
u.remotePath.SetText("vault.kdbx")
|
||||
u.remoteUsername.SetText("tjulian")
|
||||
u.remotePassword.SetText("token-1")
|
||||
|
||||
u.startOpenRemoteAction()
|
||||
result := waitForBackgroundResult(t, u)
|
||||
u.applyBackgroundResult(result)
|
||||
|
||||
if got := u.state.ErrorMessage; got != "" {
|
||||
t.Fatalf("ErrorMessage after apply = %q, want empty", got)
|
||||
}
|
||||
if got := u.vaultPath.Text(); got != cachePath {
|
||||
t.Fatalf("vaultPath = %q, want %q", got, cachePath)
|
||||
}
|
||||
if _, err := os.Stat(cachePath); err != nil {
|
||||
t.Fatalf("Stat(cachePath) error = %v", err)
|
||||
}
|
||||
if got := len(u.recentRemotes); got != 1 {
|
||||
t.Fatalf("len(recentRemotes) = %d, want 1", got)
|
||||
}
|
||||
record := u.recentRemotes[0]
|
||||
if record.LocalVaultPath != cachePath {
|
||||
t.Fatalf("recentRemotes[0].LocalVaultPath = %q, want %q", record.LocalVaultPath, cachePath)
|
||||
}
|
||||
if record.RemoteProfileID == "" || record.CredentialEntryID == "" {
|
||||
t.Fatalf("recentRemotes[0] = %#v, want binding ids populated", record)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultStatePathsUsesProvidedStateDir(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user