Share hidden vault root logic across UI and API
This commit is contained in:
+3
-13
@@ -19,6 +19,7 @@ import (
|
|||||||
"git.julianfamily.org/keepassgo/internal/passwords"
|
"git.julianfamily.org/keepassgo/internal/passwords"
|
||||||
"git.julianfamily.org/keepassgo/internal/session"
|
"git.julianfamily.org/keepassgo/internal/session"
|
||||||
"git.julianfamily.org/keepassgo/internal/vault"
|
"git.julianfamily.org/keepassgo/internal/vault"
|
||||||
|
"git.julianfamily.org/keepassgo/internal/vaultview"
|
||||||
"git.julianfamily.org/keepassgo/internal/webdav"
|
"git.julianfamily.org/keepassgo/internal/webdav"
|
||||||
keepassgov1 "git.julianfamily.org/keepassgo/proto/keepassgo/v1"
|
keepassgov1 "git.julianfamily.org/keepassgo/proto/keepassgo/v1"
|
||||||
"google.golang.org/grpc/codes"
|
"google.golang.org/grpc/codes"
|
||||||
@@ -973,19 +974,8 @@ func entryFromProtoWithModel(model vault.Model, entry *keepassgov1.Entry) vault.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func hiddenVaultRoot(model vault.Model) string {
|
|
||||||
if len(model.EntriesInPath(nil)) != 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
groups := model.ChildGroups(nil)
|
|
||||||
if len(groups) != 1 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return groups[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
func expandClientPath(model vault.Model, path []string) []string {
|
func expandClientPath(model vault.Model, path []string) []string {
|
||||||
root := hiddenVaultRoot(model)
|
root := vaultview.HiddenRoot(model)
|
||||||
if root == "" {
|
if root == "" {
|
||||||
return append([]string(nil), path...)
|
return append([]string(nil), path...)
|
||||||
}
|
}
|
||||||
@@ -999,7 +989,7 @@ func expandClientPath(model vault.Model, path []string) []string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func collapseInternalPath(model vault.Model, path []string) []string {
|
func collapseInternalPath(model vault.Model, path []string) []string {
|
||||||
root := hiddenVaultRoot(model)
|
root := vaultview.HiddenRoot(model)
|
||||||
if root == "" || len(path) == 0 || path[0] != root {
|
if root == "" || len(path) == 0 || path[0] != root {
|
||||||
return append([]string(nil), path...)
|
return append([]string(nil), path...)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -265,6 +265,46 @@ func TestVaultServiceListEntriesHidesSingleInternalVaultRoot(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestVaultServiceListEntriesHidesSingleInternalVaultRootWhenRecycleBinExists(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
client, _, cleanup := newTestClientForModel(t, vault.Model{
|
||||||
|
Entries: []vault.Entry{
|
||||||
|
{
|
||||||
|
ID: "codex-nextcloud",
|
||||||
|
Title: "Nextcloud (codex)",
|
||||||
|
Username: "jjulian",
|
||||||
|
Password: "secret-1",
|
||||||
|
URL: "https://nextcloud.example.invalid",
|
||||||
|
Path: []string{"keepass", "Joe", "codex"},
|
||||||
|
},
|
||||||
|
testAPITokenEntry(t,
|
||||||
|
apitokens.PolicyRule{Effect: apitokens.EffectAllow, Operation: apitokens.OperationListEntries, Resource: apitokens.Resource{Kind: apitokens.ResourceGroup, Path: []string{"keepass", "Joe", "codex"}}},
|
||||||
|
),
|
||||||
|
},
|
||||||
|
Groups: [][]string{
|
||||||
|
{"keepass"},
|
||||||
|
{"keepass", "Joe"},
|
||||||
|
{"keepass", "Joe", "codex"},
|
||||||
|
{"Recycle Bin"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
resp, err := client.ListEntries(tokenContext(defaultTestTokenSecret), &keepassgov1.ListEntriesRequest{
|
||||||
|
Path: []string{"Joe", "codex"},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ListEntries() error = %v", err)
|
||||||
|
}
|
||||||
|
if len(resp.Entries) != 1 {
|
||||||
|
t.Fatalf("len(ListEntries().Entries) = %d, want 1", len(resp.Entries))
|
||||||
|
}
|
||||||
|
if got := resp.Entries[0].Path; !slices.Equal(got, []string{"Joe", "codex"}) {
|
||||||
|
t.Fatalf("ListEntries().Entries[0].Path = %v, want [Joe codex]", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestVaultServiceListGroupsHidesSingleInternalVaultRoot(t *testing.T) {
|
func TestVaultServiceListGroupsHidesSingleInternalVaultRoot(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
@@ -291,6 +331,33 @@ func TestVaultServiceListGroupsHidesSingleInternalVaultRoot(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestVaultServiceListGroupsHidesSingleInternalVaultRootWhenRecycleBinExists(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
client, _, cleanup := newTestClientForModel(t, vault.Model{
|
||||||
|
Entries: []vault.Entry{
|
||||||
|
testAPITokenEntry(t,
|
||||||
|
apitokens.PolicyRule{Effect: apitokens.EffectAllow, Operation: apitokens.OperationListGroups, Resource: apitokens.Resource{Kind: apitokens.ResourceGroup, Path: []string{"keepass"}}},
|
||||||
|
),
|
||||||
|
},
|
||||||
|
Groups: [][]string{
|
||||||
|
{"keepass"},
|
||||||
|
{"keepass", "Joe"},
|
||||||
|
{"keepass", "Shared"},
|
||||||
|
{"Recycle Bin"},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
defer cleanup()
|
||||||
|
|
||||||
|
resp, err := client.ListGroups(tokenContext(defaultTestTokenSecret), &keepassgov1.ListGroupsRequest{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ListGroups() error = %v", err)
|
||||||
|
}
|
||||||
|
if !slices.Equal(resp.Names, []string{"Joe", "Shared"}) {
|
||||||
|
t.Fatalf("ListGroups().Names = %v, want [Joe Shared]", resp.Names)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestVaultServiceGetsBrowserCredentialForAuthorizedClients(t *testing.T) {
|
func TestVaultServiceGetsBrowserCredentialForAuthorizedClients(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import (
|
|||||||
"git.julianfamily.org/keepassgo/internal/autofillcache"
|
"git.julianfamily.org/keepassgo/internal/autofillcache"
|
||||||
"git.julianfamily.org/keepassgo/internal/session"
|
"git.julianfamily.org/keepassgo/internal/session"
|
||||||
"git.julianfamily.org/keepassgo/internal/vault"
|
"git.julianfamily.org/keepassgo/internal/vault"
|
||||||
|
"git.julianfamily.org/keepassgo/internal/vaultview"
|
||||||
"git.julianfamily.org/keepassgo/internal/webdav"
|
"git.julianfamily.org/keepassgo/internal/webdav"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -1266,21 +1267,7 @@ func (u *ui) hiddenVaultRoot() string {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
if len(model.EntriesInPath(nil)) != 0 {
|
return vaultview.HiddenRoot(model)
|
||||||
return ""
|
|
||||||
}
|
|
||||||
groups := model.ChildGroups(nil)
|
|
||||||
roots := make([]string, 0, len(groups))
|
|
||||||
for _, group := range groups {
|
|
||||||
if group == "Recycle Bin" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
roots = append(roots, group)
|
|
||||||
}
|
|
||||||
if len(roots) != 1 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return roots[0]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *ui) enterHiddenVaultRoot() {
|
func (u *ui) enterHiddenVaultRoot() {
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package vaultview
|
||||||
|
|
||||||
|
import "git.julianfamily.org/keepassgo/internal/vault"
|
||||||
|
|
||||||
|
// HiddenRoot returns the single synthetic top-level vault group that should be
|
||||||
|
// treated as an internal storage root rather than as a user-visible group.
|
||||||
|
func HiddenRoot(model vault.Model) string {
|
||||||
|
if len(model.EntriesInPath(nil)) != 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
groups := model.ChildGroups(nil)
|
||||||
|
roots := make([]string, 0, len(groups))
|
||||||
|
for _, group := range groups {
|
||||||
|
if group == "Recycle Bin" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
roots = append(roots, group)
|
||||||
|
}
|
||||||
|
if len(roots) != 1 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return roots[0]
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package vaultview
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"git.julianfamily.org/keepassgo/internal/vault"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHiddenRootIgnoresRecycleBin(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
model := vault.Model{
|
||||||
|
Entries: []vault.Entry{
|
||||||
|
{ID: "entry-1", Title: "Vault Console", Path: []string{"keepass", "Crew", "Internet"}},
|
||||||
|
},
|
||||||
|
Groups: [][]string{
|
||||||
|
{"keepass"},
|
||||||
|
{"keepass", "Crew"},
|
||||||
|
{"Recycle Bin"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if got := HiddenRoot(model); got != "keepass" {
|
||||||
|
t.Fatalf("HiddenRoot() = %q, want %q", got, "keepass")
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user