| // Copyright (c) HashiCorp, Inc. |
| // SPDX-License-Identifier: MPL-2.0 |
| |
| package framework |
| |
| import ( |
| "context" |
| "encoding/json" |
| "fmt" |
| |
| "github.com/hashicorp/vault/sdk/helper/jsonutil" |
| "github.com/hashicorp/vault/sdk/logical" |
| ) |
| |
| // PathStruct can be used to generate a path that stores a struct |
| // in the storage. This structure is a map[string]interface{} but the |
| // types are set according to the schema in this structure. |
| type PathStruct struct { |
| Name string |
| Path string |
| Schema map[string]*FieldSchema |
| HelpSynopsis string |
| HelpDescription string |
| |
| Read bool |
| } |
| |
| // Get reads the structure. |
| func (p *PathStruct) Get(ctx context.Context, s logical.Storage) (map[string]interface{}, error) { |
| entry, err := s.Get(ctx, fmt.Sprintf("struct/%s", p.Name)) |
| if err != nil { |
| return nil, err |
| } |
| if entry == nil { |
| return nil, nil |
| } |
| |
| var result map[string]interface{} |
| if err := jsonutil.DecodeJSON(entry.Value, &result); err != nil { |
| return nil, err |
| } |
| |
| return result, nil |
| } |
| |
| // Put writes the structure. |
| func (p *PathStruct) Put(ctx context.Context, s logical.Storage, v map[string]interface{}) error { |
| bytes, err := json.Marshal(v) |
| if err != nil { |
| return err |
| } |
| |
| return s.Put(ctx, &logical.StorageEntry{ |
| Key: fmt.Sprintf("struct/%s", p.Name), |
| Value: bytes, |
| }) |
| } |
| |
| // Delete removes the structure. |
| func (p *PathStruct) Delete(ctx context.Context, s logical.Storage) error { |
| return s.Delete(ctx, fmt.Sprintf("struct/%s", p.Name)) |
| } |
| |
| // Paths are the paths to append to the Backend paths. |
| func (p *PathStruct) Paths() []*Path { |
| // The single path we support to read/write this config |
| path := &Path{ |
| Pattern: p.Path, |
| Fields: p.Schema, |
| |
| Callbacks: map[logical.Operation]OperationFunc{ |
| logical.CreateOperation: p.pathWrite(), |
| logical.UpdateOperation: p.pathWrite(), |
| logical.DeleteOperation: p.pathDelete(), |
| }, |
| |
| ExistenceCheck: p.pathExistenceCheck(), |
| |
| HelpSynopsis: p.HelpSynopsis, |
| HelpDescription: p.HelpDescription, |
| } |
| |
| // If we support reads, add that |
| if p.Read { |
| path.Callbacks[logical.ReadOperation] = p.pathRead() |
| } |
| |
| return []*Path{path} |
| } |
| |
| func (p *PathStruct) pathRead() OperationFunc { |
| return func(ctx context.Context, req *logical.Request, d *FieldData) (*logical.Response, error) { |
| v, err := p.Get(ctx, req.Storage) |
| if err != nil { |
| return nil, err |
| } |
| |
| return &logical.Response{ |
| Data: v, |
| }, nil |
| } |
| } |
| |
| func (p *PathStruct) pathWrite() OperationFunc { |
| return func(ctx context.Context, req *logical.Request, d *FieldData) (*logical.Response, error) { |
| err := p.Put(ctx, req.Storage, d.Raw) |
| return nil, err |
| } |
| } |
| |
| func (p *PathStruct) pathDelete() OperationFunc { |
| return func(ctx context.Context, req *logical.Request, d *FieldData) (*logical.Response, error) { |
| err := p.Delete(ctx, req.Storage) |
| return nil, err |
| } |
| } |
| |
| func (p *PathStruct) pathExistenceCheck() ExistenceFunc { |
| return func(ctx context.Context, req *logical.Request, d *FieldData) (bool, error) { |
| v, err := p.Get(ctx, req.Storage) |
| if err != nil { |
| return false, err |
| } |
| |
| return v != nil, nil |
| } |
| } |