From 14b7cd28409d8fd8956e21c549130b3fe1141b9f Mon Sep 17 00:00:00 2001 From: AlanD20 Date: Thu, 30 May 2024 11:16:23 +0200 Subject: [PATCH] Prompt to unlock individual item when getting secret from keyring Signed-off-by: AlanD20 --- keyring_mock.go | 58 ++++++++++++++++++++++++++++++++++++++------ keyring_mock_test.go | 18 ++++++++++++++ keyring_unix.go | 6 +++++ 3 files changed, 75 insertions(+), 7 deletions(-) diff --git a/keyring_mock.go b/keyring_mock.go index 0e514ea..e0dcad6 100644 --- a/keyring_mock.go +++ b/keyring_mock.go @@ -1,7 +1,12 @@ package keyring +type mockProviderItem struct { + Value string + Locked bool +} + type mockProvider struct { - mockStore map[string]map[string]string + mockStore map[string]map[string]*mockProviderItem mockError error } @@ -12,12 +17,12 @@ func (m *mockProvider) Set(service, user, pass string) error { return m.mockError } if m.mockStore == nil { - m.mockStore = make(map[string]map[string]string) + m.mockStore = make(map[string]map[string]*mockProviderItem) } if m.mockStore[service] == nil { - m.mockStore[service] = make(map[string]string) + m.mockStore[service] = make(map[string]*mockProviderItem) } - m.mockStore[service][user] = pass + m.mockStore[service][user] = &mockProviderItem{Value: pass, Locked: true} return nil } @@ -27,8 +32,12 @@ func (m *mockProvider) Get(service, user string) (string, error) { return "", m.mockError } if b, ok := m.mockStore[service]; ok { - if v, ok := b[user]; ok { - return v, nil + if item, ok := b[user]; ok { + if item.Locked { + return "", ErrNotFound + } + _ = m.Lock(service, user) + return item.Value, nil } } return "", ErrNotFound @@ -41,7 +50,10 @@ func (m *mockProvider) Delete(service, user string) error { } if m.mockStore != nil { if _, ok := m.mockStore[service]; ok { - if _, ok := m.mockStore[service][user]; ok { + if item, ok := m.mockStore[service][user]; ok { + if item.Locked { + return ErrNotFound + } delete(m.mockStore[service], user) return nil } @@ -50,6 +62,38 @@ func (m *mockProvider) Delete(service, user string) error { return ErrNotFound } +// Unlock unlocks item from the keyring given a service name and a user +func (m *mockProvider) Unlock(service, user string) error { + if m.mockError != nil { + return m.mockError + } + if m.mockStore != nil { + if _, ok := m.mockStore[service]; ok { + if item, ok := m.mockStore[service][user]; ok { + item.Locked = false + return nil + } + } + } + return ErrNotFound +} + +// Lock locks item from the keyring given a service name and a user +func (m *mockProvider) Lock(service, user string) error { + if m.mockError != nil { + return m.mockError + } + if m.mockStore != nil { + if _, ok := m.mockStore[service]; ok { + if item, ok := m.mockStore[service][user]; ok { + item.Locked = true + return nil + } + } + } + return ErrNotFound +} + // MockInit sets the provider to a mocked memory store func MockInit() { provider = &mockProvider{} diff --git a/keyring_mock_test.go b/keyring_mock_test.go index 11931b2..485c3fe 100644 --- a/keyring_mock_test.go +++ b/keyring_mock_test.go @@ -22,6 +22,7 @@ func TestMockGet(t *testing.T) { t.Errorf("Should not fail, got: %s", err) } + _ = mp.Unlock(service, user) pw, err := mp.Get(service, user) if err != nil { t.Errorf("Should not fail, got: %s", err) @@ -32,6 +33,22 @@ func TestMockGet(t *testing.T) { } } +// TestGetLocked tests getting a locked password from the keyring. +func TestMockGetLocked(t *testing.T) { + mp := mockProvider{} + err := mp.Set(service, user, password) + if err != nil { + t.Errorf("Should not fail, got: %s", err) + } + + pwd, err := mp.Get(service, user) + assertError(t, err, ErrNotFound) + + if pwd != "" { + t.Errorf("Should not return item value, got: %s", pwd) + } +} + // TestGetNonExisting tests getting a secret not in the keyring. func TestMockGetNonExisting(t *testing.T) { mp := mockProvider{} @@ -49,6 +66,7 @@ func TestMockDelete(t *testing.T) { t.Errorf("Should not fail, got: %s", err) } + _ = mp.Unlock(service, user) err = mp.Delete(service, user) if err != nil { t.Errorf("Should not fail, got: %s", err) diff --git a/keyring_unix.go b/keyring_unix.go index 28537e7..523f6a3 100644 --- a/keyring_unix.go +++ b/keyring_unix.go @@ -95,6 +95,12 @@ func (s secretServiceProvider) Get(service, user string) (string, error) { } defer svc.Close(session) + // unlock if invdividual item is locked + err = svc.Unlock(item) + if err != nil { + return "", err + } + secret, err := svc.GetSecret(item, session.Path()) if err != nil { return "", err