Clean up browser bridge and mutation helpers

This commit is contained in:
Joe Julian
2026-04-12 00:02:50 -07:00
parent dc7dd19543
commit 57870ca4f1
8 changed files with 243 additions and 210 deletions
+62 -61
View File
@@ -113,9 +113,6 @@ func (s *Server) GetSessionStatus(ctx context.Context, _ *keepassgov1.GetSession
if err != nil {
return nil, err
}
s.mu.RLock()
defer s.mu.RUnlock()
pendingApprovals := s.approvals.Pending()
var tokenPending uint32
for _, pending := range pendingApprovals {
@@ -123,11 +120,16 @@ func (s *Server) GetSessionStatus(ctx context.Context, _ *keepassgov1.GetSession
tokenPending++
}
}
s.mu.RLock()
locked := s.locked
dirty := s.dirty
entryCount := uint32(len(s.model.Entries))
s.mu.RUnlock()
return &keepassgov1.GetSessionStatusResponse{
Locked: s.locked,
Dirty: s.dirty,
EntryCount: uint32(len(s.model.Entries)),
Locked: locked,
Dirty: dirty,
EntryCount: entryCount,
PendingApprovalCount: uint32(len(pendingApprovals)),
TokenPendingApprovalCount: tokenPending,
}, nil
@@ -486,76 +488,75 @@ func (s *Server) ListGroups(ctx context.Context, req *keepassgov1.ListGroupsRequ
}, nil
}
func (s *Server) CreateGroup(ctx context.Context, req *keepassgov1.CreateGroupRequest) (*keepassgov1.CreateGroupResponse, error) {
func (s *Server) mutateAuthorizedVisiblePath(ctx context.Context, clientPath []string, op apitokens.Operation, mutate func(*vault.Model, []string) error) error {
model, locked := s.snapshotModel()
if locked {
return nil, status.Error(codes.FailedPrecondition, "vault is locked")
return status.Error(codes.FailedPrecondition, "vault is locked")
}
parentPath := expandClientPath(visibleModel(model), req.GetParentPath())
if _, err := s.authorizePathRequest(ctx, apitokens.OperationMutateGroup, parentPath); err != nil {
return nil, err
internalPath := expandClientPath(visibleModel(model), clientPath)
if _, err := s.authorizePathRequest(ctx, op, internalPath); err != nil {
return err
}
return s.mutateAuthorizedModel(func() error { return nil }, func(model *vault.Model) error {
return mutate(model, internalPath)
})
}
func (s *Server) mutateAuthorizedModel(authorize func() error, mutate func(*vault.Model) error) error {
if err := authorize(); err != nil {
return err
}
s.mu.Lock()
defer s.mu.Unlock()
s.model.CreateGroup(parentPath, req.GetName())
if err := mutate(&s.model); err != nil {
return err
}
s.dirty = true
s.syncMutationLocked()
return nil
}
func (s *Server) CreateGroup(ctx context.Context, req *keepassgov1.CreateGroupRequest) (*keepassgov1.CreateGroupResponse, error) {
if err := s.mutateAuthorizedVisiblePath(ctx, req.GetParentPath(), apitokens.OperationMutateGroup, func(model *vault.Model, parentPath []string) error {
model.CreateGroup(parentPath, req.GetName())
return nil
}); err != nil {
return nil, err
}
return &keepassgov1.CreateGroupResponse{}, nil
}
func (s *Server) RenameGroup(ctx context.Context, req *keepassgov1.RenameGroupRequest) (*keepassgov1.RenameGroupResponse, error) {
model, locked := s.snapshotModel()
if locked {
return nil, status.Error(codes.FailedPrecondition, "vault is locked")
}
groupPath := expandClientPath(visibleModel(model), req.GetPath())
if _, err := s.authorizePathRequest(ctx, apitokens.OperationMutateGroup, groupPath); err != nil {
if err := s.mutateAuthorizedVisiblePath(ctx, req.GetPath(), apitokens.OperationMutateGroup, func(model *vault.Model, groupPath []string) error {
if err := model.RenameGroup(groupPath, req.GetNewName()); err != nil {
if errors.Is(err, vault.ErrEntryNotFound) {
return status.Error(codes.NotFound, err.Error())
}
return status.Errorf(codes.Internal, "rename group: %v", err)
}
return nil
}); err != nil {
return nil, err
}
s.mu.Lock()
defer s.mu.Unlock()
if err := s.model.RenameGroup(groupPath, req.GetNewName()); err != nil {
if errors.Is(err, vault.ErrEntryNotFound) {
return nil, status.Error(codes.NotFound, err.Error())
}
return nil, status.Errorf(codes.Internal, "rename group: %v", err)
}
s.dirty = true
s.syncMutationLocked()
return &keepassgov1.RenameGroupResponse{}, nil
}
func (s *Server) DeleteGroup(ctx context.Context, req *keepassgov1.DeleteGroupRequest) (*keepassgov1.DeleteGroupResponse, error) {
model, locked := s.snapshotModel()
if locked {
return nil, status.Error(codes.FailedPrecondition, "vault is locked")
}
groupPath := expandClientPath(visibleModel(model), req.GetPath())
if _, err := s.authorizePathRequest(ctx, apitokens.OperationMutateGroup, groupPath); err != nil {
if err := s.mutateAuthorizedVisiblePath(ctx, req.GetPath(), apitokens.OperationMutateGroup, func(model *vault.Model, groupPath []string) error {
if err := model.DeleteGroup(groupPath); err != nil {
switch {
case errors.Is(err, vault.ErrEntryNotFound):
return status.Error(codes.NotFound, err.Error())
case errors.Is(err, vault.ErrGroupNotEmpty):
return status.Error(codes.FailedPrecondition, err.Error())
default:
return status.Errorf(codes.Internal, "delete group: %v", err)
}
}
return nil
}); err != nil {
return nil, err
}
s.mu.Lock()
defer s.mu.Unlock()
if err := s.model.DeleteGroup(groupPath); err != nil {
switch {
case errors.Is(err, vault.ErrEntryNotFound):
return nil, status.Error(codes.NotFound, err.Error())
case errors.Is(err, vault.ErrGroupNotEmpty):
return nil, status.Error(codes.FailedPrecondition, err.Error())
default:
return nil, status.Errorf(codes.Internal, "delete group: %v", err)
}
}
s.dirty = true
s.syncMutationLocked()
return &keepassgov1.DeleteGroupResponse{}, nil
}
@@ -572,12 +573,12 @@ func (s *Server) UpsertEntry(ctx context.Context, req *keepassgov1.UpsertEntryRe
if _, err := s.authorizeUpsertEntryRequest(ctx, entry); err != nil {
return nil, err
}
s.mu.Lock()
s.model.UpsertEntry(entry)
s.dirty = true
s.syncMutationLocked()
s.mu.Unlock()
if err := s.mutateAuthorizedModel(func() error { return nil }, func(model *vault.Model) error {
model.UpsertEntry(entry)
return nil
}); err != nil {
return nil, err
}
return &keepassgov1.UpsertEntryResponse{Entry: entryToProtoWithModel(visibleModel(model), entry)}, nil
}