feat: harden secret unlock and deletion
This commit is contained in:
+20
-1
@@ -1322,8 +1322,13 @@ func (a *App) PluginSecretsStatus(pluginID string) (map[string]interface{}, stri
|
||||
if err != nil {
|
||||
return nil, err.Error()
|
||||
}
|
||||
initialized, err := session.Initialized()
|
||||
if err != nil {
|
||||
return nil, err.Error()
|
||||
}
|
||||
return map[string]interface{}{
|
||||
"unlocked": session.Unlocked(),
|
||||
"initialized": initialized,
|
||||
"unlocked": session.Unlocked(),
|
||||
}, ""
|
||||
}
|
||||
|
||||
@@ -1397,6 +1402,20 @@ func (a *App) PluginSecretsWrite(pluginID string, rawRecord map[string]interface
|
||||
return secretRecordMap(written, false), ""
|
||||
}
|
||||
|
||||
func (a *App) PluginSecretsDelete(pluginID, secretID string) string {
|
||||
if err := a.requirePluginSecretsAccess(pluginID, true); err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
store, err := a.requireUnlockedSecretStore()
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
if err := store.Delete(secretID); err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (a *App) PluginSecretsCopyLink(pluginID, secretID string) (string, string) {
|
||||
if err := a.requirePluginSecretsAccess(pluginID, false); err != nil {
|
||||
return "", err.Error()
|
||||
|
||||
@@ -1628,6 +1628,9 @@ func TestPluginSecretsRequirePermissionsAndUnlock(t *testing.T) {
|
||||
if status["unlocked"] == true {
|
||||
t.Fatalf("new secret session should be locked: %+v", status)
|
||||
}
|
||||
if status["initialized"] == true {
|
||||
t.Fatalf("new secret session should not be initialized: %+v", status)
|
||||
}
|
||||
|
||||
if errStr := app.PluginSecretsUnlock("no.storage", "master password"); !strings.Contains(errStr, "secrets.read") {
|
||||
t.Fatalf("PluginSecretsUnlock err = %q, want secrets.read permission error", errStr)
|
||||
@@ -1636,6 +1639,10 @@ func TestPluginSecretsRequirePermissionsAndUnlock(t *testing.T) {
|
||||
t.Fatalf("PluginSecretsList before unlock err = %q, want locked", errStr)
|
||||
}
|
||||
|
||||
if errStr := app.PluginSecretsUnlock("secrets.plugin", "123123"); !strings.Contains(errStr, "at least 8 characters") {
|
||||
t.Fatalf("weak PluginSecretsUnlock err = %q, want minimum length error", errStr)
|
||||
}
|
||||
|
||||
if errStr := app.PluginSecretsUnlock("secrets.plugin", "master password"); errStr != "" {
|
||||
t.Fatalf("PluginSecretsUnlock: %s", errStr)
|
||||
}
|
||||
@@ -1646,6 +1653,9 @@ func TestPluginSecretsRequirePermissionsAndUnlock(t *testing.T) {
|
||||
if status["unlocked"] != true {
|
||||
t.Fatalf("secret session not unlocked: %+v", status)
|
||||
}
|
||||
if status["initialized"] != true {
|
||||
t.Fatalf("secret session not initialized: %+v", status)
|
||||
}
|
||||
|
||||
writeResult, errStr := app.PluginSecretsWrite("secrets.plugin", map[string]interface{}{
|
||||
"id": "client-a.database",
|
||||
@@ -1694,6 +1704,17 @@ func TestPluginSecretsRequirePermissionsAndUnlock(t *testing.T) {
|
||||
if link != "[Client A Database](verstak-secret://client-a.database)" {
|
||||
t.Fatalf("link = %q", link)
|
||||
}
|
||||
|
||||
if errStr := app.PluginSecretsDelete("secrets.plugin", "client-a.database"); errStr != "" {
|
||||
t.Fatalf("PluginSecretsDelete: %s", errStr)
|
||||
}
|
||||
list, errStr = app.PluginSecretsList("secrets.plugin")
|
||||
if errStr != "" {
|
||||
t.Fatalf("PluginSecretsList after delete: %s", errStr)
|
||||
}
|
||||
if len(list) != 0 {
|
||||
t.Fatalf("PluginSecretsList after delete = %+v, want empty", list)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPluginSecretsRejectWrongMasterPasswordAcrossSessions(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user