Expose API approval prompts to app state and UI
This commit is contained in:
@@ -6,6 +6,8 @@ import (
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"git.julianfamily.org/keepassgo/apiapproval"
|
||||
"git.julianfamily.org/keepassgo/apitokens"
|
||||
"git.julianfamily.org/keepassgo/vault"
|
||||
"git.julianfamily.org/keepassgo/webdav"
|
||||
)
|
||||
@@ -81,8 +83,14 @@ type RemoteOpenableSession interface {
|
||||
OpenRemote(webdav.Client, string, vault.MasterKey) error
|
||||
}
|
||||
|
||||
type ApprovalManager interface {
|
||||
Pending() []apiapproval.Request
|
||||
Resolve(string, apiapproval.Outcome) (apiapproval.Request, *apitokens.PolicyRule, error)
|
||||
}
|
||||
|
||||
type State struct {
|
||||
Session CurrentSession
|
||||
Approvals ApprovalManager
|
||||
Section Section
|
||||
CurrentPath []string
|
||||
SearchQuery string
|
||||
@@ -92,6 +100,21 @@ type State struct {
|
||||
ErrorMessage string
|
||||
}
|
||||
|
||||
func (s *State) PendingApprovals() []apiapproval.Request {
|
||||
if s.Approvals == nil {
|
||||
return nil
|
||||
}
|
||||
return s.Approvals.Pending()
|
||||
}
|
||||
|
||||
func (s *State) ResolveApproval(id string, outcome apiapproval.Outcome) error {
|
||||
if s.Approvals == nil {
|
||||
return fmt.Errorf("approval manager is not configured")
|
||||
}
|
||||
_, _, err := s.Approvals.Resolve(id, outcome)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *State) ShowSection(section Section) {
|
||||
s.Section = section
|
||||
s.CurrentPath = nil
|
||||
|
||||
@@ -5,6 +5,8 @@ import (
|
||||
"slices"
|
||||
"testing"
|
||||
|
||||
"git.julianfamily.org/keepassgo/apiapproval"
|
||||
"git.julianfamily.org/keepassgo/apitokens"
|
||||
"git.julianfamily.org/keepassgo/session"
|
||||
"git.julianfamily.org/keepassgo/vault"
|
||||
"git.julianfamily.org/keepassgo/webdav"
|
||||
@@ -41,6 +43,36 @@ func TestVisibleEntriesFollowsCurrentPathWithoutSearch(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestPendingApprovalsReturnsManagerRequests(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
state := State{
|
||||
Approvals: &stubApprovalManager{
|
||||
pending: []apiapproval.Request{
|
||||
{ID: "approval-1", TokenName: "CLI", Operation: apitokens.OperationListEntries},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
got := state.PendingApprovals()
|
||||
if len(got) != 1 || got[0].ID != "approval-1" {
|
||||
t.Fatalf("PendingApprovals() = %#v, want approval-1", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestResolveApprovalDelegatesToManager(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
manager := &stubApprovalManager{}
|
||||
state := State{Approvals: manager}
|
||||
if err := state.ResolveApproval("approval-1", apiapproval.OutcomeAllowPermanent); err != nil {
|
||||
t.Fatalf("ResolveApproval() error = %v", err)
|
||||
}
|
||||
if manager.lastID != "approval-1" || manager.lastOutcome != apiapproval.OutcomeAllowPermanent {
|
||||
t.Fatalf("ResolveApproval() delegated (%q, %q), want (approval-1, allow-permanent)", manager.lastID, manager.lastOutcome)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVisibleEntriesUsesGlobalSearchWhenQueryPresent(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
@@ -1378,3 +1410,19 @@ func (s *lifecycleStubSession) ChangeMasterKey(key vault.MasterKey) error {
|
||||
s.changedKey = key
|
||||
return nil
|
||||
}
|
||||
|
||||
type stubApprovalManager struct {
|
||||
pending []apiapproval.Request
|
||||
lastID string
|
||||
lastOutcome apiapproval.Outcome
|
||||
}
|
||||
|
||||
func (s stubApprovalManager) Pending() []apiapproval.Request {
|
||||
return append([]apiapproval.Request(nil), s.pending...)
|
||||
}
|
||||
|
||||
func (s *stubApprovalManager) Resolve(id string, outcome apiapproval.Outcome) (apiapproval.Request, *apitokens.PolicyRule, error) {
|
||||
s.lastID = id
|
||||
s.lastOutcome = outcome
|
||||
return apiapproval.Request{ID: id}, nil, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user