Match remote sync credentials by host
This commit is contained in:
@@ -10,6 +10,7 @@ import (
|
||||
"image"
|
||||
"image/color"
|
||||
"io"
|
||||
"net/url"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@@ -2319,6 +2320,34 @@ func normalizeRemoteCredentialURL(raw string) string {
|
||||
return raw
|
||||
}
|
||||
|
||||
func remoteCredentialURLMatches(candidate, target string) bool {
|
||||
candidate = normalizeRemoteCredentialURL(candidate)
|
||||
target = normalizeRemoteCredentialURL(target)
|
||||
if candidate == "" || target == "" {
|
||||
return false
|
||||
}
|
||||
if candidate == target {
|
||||
return true
|
||||
}
|
||||
candidateURL, err := url.Parse(candidate)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
targetURL, err := url.Parse(target)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
if !strings.EqualFold(candidateURL.Hostname(), targetURL.Hostname()) {
|
||||
return false
|
||||
}
|
||||
candidatePath := strings.TrimRight(candidateURL.EscapedPath(), "/")
|
||||
targetPath := strings.TrimRight(targetURL.EscapedPath(), "/")
|
||||
if candidatePath == "" || candidatePath == "/" || targetPath == "" || targetPath == "/" {
|
||||
return true
|
||||
}
|
||||
return strings.HasPrefix(targetPath, candidatePath) || strings.HasPrefix(candidatePath, targetPath)
|
||||
}
|
||||
|
||||
func (u *ui) matchingAdvancedSyncRemoteCredentialEntries() []vault.Entry {
|
||||
if sanitizeSyncSourceMode(u.syncSourceMode) != syncSourceRemote {
|
||||
return nil
|
||||
@@ -2346,7 +2375,7 @@ func (u *ui) matchingAdvancedSyncRemoteCredentialEntries() []vault.Entry {
|
||||
matches = append(matches, entry)
|
||||
}
|
||||
for _, entry := range entries {
|
||||
if normalizeRemoteCredentialURL(entry.URL) != baseURL {
|
||||
if !remoteCredentialURLMatches(entry.URL, baseURL) {
|
||||
continue
|
||||
}
|
||||
appendMatch(entry)
|
||||
@@ -2364,7 +2393,7 @@ func (u *ui) matchingAdvancedSyncRemoteCredentialEntries() []vault.Entry {
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
if normalizeRemoteCredentialURL(profile.BaseURL) != baseURL {
|
||||
if !remoteCredentialURLMatches(profile.BaseURL, baseURL) {
|
||||
continue
|
||||
}
|
||||
if remotePath != "" && strings.TrimSpace(profile.Path) != remotePath && strings.TrimSpace(record.Path) != remotePath {
|
||||
|
||||
@@ -6732,6 +6732,55 @@ func TestUIAdvancedSyncMatchingRemoteCredentialEntriesUsesBaseURL(t *testing.T)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUIAdvancedSyncMatchingRemoteCredentialEntriesUsesMatchingHost(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
u := newUIWithModel("desktop", vault.Model{
|
||||
Entries: []vault.Entry{
|
||||
{ID: "entry-1", Title: "Mint WebDAV", Username: "charliecroker", URL: "https://dav.example.invalid", Path: []string{"Crew", "Signals"}},
|
||||
{ID: "entry-2", Title: "Bellagio WebDAV Sign-In", Username: "linuscaldwell", URL: "https://dav.example.invalid/remote.php/dav", Path: []string{"Crew", "Signals"}},
|
||||
{ID: "entry-3", Title: "Bank Console", Username: "stevefrezelli", URL: "https://insidejob.example.invalid", Path: []string{"Crew", "Signals"}},
|
||||
},
|
||||
})
|
||||
u.syncSourceMode = syncSourceRemote
|
||||
u.syncRemoteBaseURL.SetText("https://dav.example.invalid/remote.php/dav")
|
||||
|
||||
got := u.matchingAdvancedSyncRemoteCredentialEntries()
|
||||
if len(got) != 2 {
|
||||
t.Fatalf("len(matchingAdvancedSyncRemoteCredentialEntries()) = %d, want 2", len(got))
|
||||
}
|
||||
gotIDs := []string{got[0].ID, got[1].ID}
|
||||
slices.Sort(gotIDs)
|
||||
if !slices.Equal(gotIDs, []string{"entry-1", "entry-2"}) {
|
||||
t.Fatalf("matchingAdvancedSyncRemoteCredentialEntries() ids = %v, want [entry-1 entry-2]", gotIDs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUIRemoteSyncSetupMatchingCredentialsUsesMatchingHost(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
u := newUIWithModel("desktop", vault.Model{
|
||||
Entries: []vault.Entry{
|
||||
{ID: "entry-1", Title: "Mint WebDAV", Username: "charliecroker", URL: "https://dav.example.invalid", Path: []string{"Crew", "Signals"}},
|
||||
{ID: "entry-2", Title: "Bellagio WebDAV Sign-In", Username: "linuscaldwell", URL: "https://dav.example.invalid/remote.php/dav", Path: []string{"Crew", "Signals"}},
|
||||
},
|
||||
})
|
||||
u.syncDialogPurpose = syncDialogPurposeRemoteSetup
|
||||
u.syncSourceMode = syncSourceRemote
|
||||
u.syncDirection = syncDirectionPush
|
||||
u.syncRemoteBaseURL.SetText("https://dav.example.invalid/remote.php/dav")
|
||||
|
||||
got := u.matchingAdvancedSyncRemoteCredentialEntries()
|
||||
if len(got) != 2 {
|
||||
t.Fatalf("len(matchingAdvancedSyncRemoteCredentialEntries()) = %d, want 2 in remote setup flow", len(got))
|
||||
}
|
||||
gotIDs := []string{got[0].ID, got[1].ID}
|
||||
slices.Sort(gotIDs)
|
||||
if !slices.Equal(gotIDs, []string{"entry-1", "entry-2"}) {
|
||||
t.Fatalf("matchingAdvancedSyncRemoteCredentialEntries() ids = %v, want [entry-1 entry-2] in remote setup flow", gotIDs)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUIAdvancedSyncMatchingRemoteCredentialEntriesUsesSavedBindingForCurrentVault(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user