diff --git a/CHANGELOG.md b/CHANGELOG.md index c3040d0..70fdd3a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [0.1.7] - 2024-04-24 + +## Added + +-- Fallback method for mounts listing when user doesnt access to `sys/mounts` + ## [0.1.5] - 2024-04-18 ## Fixed diff --git a/internal/models/models.go b/internal/models/models.go index 1e743e2..ed3397b 100644 --- a/internal/models/models.go +++ b/internal/models/models.go @@ -44,6 +44,12 @@ type MountConfigOutput struct { PluginName string `json:"plugin_name,omitempty" mapstructure:"plugin_name"` } +type UiMountsResponse struct { + Data struct { + Secret map[string]*MountOutput `json:"secret"` + } `json:"data"` +} + type UserLockoutConfigOutput struct { LockoutThreshold uint `json:"lockout_threshold,omitempty" structs:"lockout_threshold" mapstructure:"lockout_threshold"` LockoutDuration int `json:"lockout_duration,omitempty" structs:"lockout_duration" mapstructure:"lockout_duration"` diff --git a/internal/vault/mounts.go b/internal/vault/mounts.go index 11442bf..457c264 100644 --- a/internal/vault/mounts.go +++ b/internal/vault/mounts.go @@ -1,20 +1,20 @@ package vault import ( + "encoding/json" "fmt" - "strings" + "io" "github.com/dkyanakiev/vaulty/internal/models" "github.com/hashicorp/vault/api" ) func (v *Vault) ListMounts() (map[string]*models.MountOutput, error) { + apiMountList, err := v.vault.Sys().ListMounts() if err != nil { - if strings.Contains(err.Error(), "route entry not found") { - return make(map[string]*models.MountOutput), nil - } - return nil, fmt.Errorf("failed to retrieve secret mounts: %w", err) + v.Logger.Warn().Err(err).Msg("Unable to access sys/mounts, attempting to use fallback method.\n") + return v.listMountsFallback() } // Convert api.MountOutput to MountOutput @@ -22,11 +22,37 @@ func (v *Vault) ListMounts() (map[string]*models.MountOutput, error) { for k, v := range apiMountList { mountList[k] = toMount(v) } - return mountList, nil } +func (v *Vault) listMountsFallback() (map[string]*models.MountOutput, error) { + + resp, err := v.vault.Logical().ReadRaw("/sys/internal/ui/mounts") + if err != nil { + return nil, fmt.Errorf("failed to retrieve secret mounts: %w", err) + } + + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("failed to read response body: %w", err) + } + + var response models.UiMountsResponse + err = json.Unmarshal(body, &response) + if err != nil { + return nil, fmt.Errorf("failed to unmarshal response: %w", err) + } + + // Convert models.MountOutput to api.MountOutput + mountList := make(map[string]*models.MountOutput) + for k, v := range response.Data.Secret { + mountList[k] = v + } + + return mountList, nil +} + func (v *Vault) AllMounts() (map[string]*models.MountOutput, error) { mounts, err := v.ListMounts()