...

Source file src/edge-infra.dev/pkg/sds/emergencyaccess/msgdata/v2_request.go

Documentation: edge-infra.dev/pkg/sds/emergencyaccess/msgdata

     1  package msgdata
     2  
     3  import (
     4  	"encoding/json"
     5  	"errors"
     6  	"fmt"
     7  
     8  	"edge-infra.dev/pkg/sds/emergencyaccess/apierror"
     9  	"edge-infra.dev/pkg/sds/emergencyaccess/eaconst"
    10  )
    11  
    12  type v2_0CommandRequest struct {
    13  	ReqAttr map[string]string `json:"attributes"`
    14  	ReqData v2Command         `json:"data"`
    15  }
    16  
    17  // Create a structured v2.0 request from a full command string
    18  func NewV2_0Request(payload string) (req Request, err error) {
    19  	requestType := determineRequestType(payload)
    20  	name, args, err := parsePayload(payload)
    21  	if err != nil {
    22  		return nil, apierror.E(apierror.ErrInvalidCommand, err)
    23  	}
    24  	attr := map[string]string{
    25  		eaconst.VersionKey:     string(eaconst.MessageVersion2_0),
    26  		eaconst.RequestTypeKey: string(requestType),
    27  	}
    28  	switch requestType {
    29  	case eaconst.Command:
    30  		r := v2_0CommandRequest{
    31  			ReqData: v2Command{
    32  				Command: name,
    33  				Args:    args,
    34  			},
    35  			ReqAttr: attr,
    36  		}
    37  		if err := r.validate(); err != nil {
    38  			return nil, err
    39  		}
    40  		req = r
    41  	case eaconst.Executable:
    42  		r := v2_0ExecutableRequest{
    43  			ReqData: v2Executable{
    44  				Executable: executable{
    45  					Name: stripExecutablePrefix(name),
    46  					// Contents not expected to be populated at this point
    47  				},
    48  				Args: args,
    49  			},
    50  			ReqAttr: attr,
    51  		}
    52  		if err := r.validate(); err != nil {
    53  			return nil, err
    54  		}
    55  		req = &r
    56  	default:
    57  		return nil, fmt.Errorf("request type %q not supported", requestType)
    58  	}
    59  	return req, nil
    60  }
    61  
    62  type v2Command struct {
    63  	Command string   `json:"command"`
    64  	Args    []string `json:"args"`
    65  }
    66  
    67  func (v v2_0CommandRequest) AddAttribute(key, val string) {
    68  	if _, ok := v.ReqAttr[key]; !ok {
    69  		v.ReqAttr[key] = val
    70  	}
    71  }
    72  
    73  func (v v2_0CommandRequest) Attributes() map[string]string {
    74  	return deepCopyMap(v.ReqAttr)
    75  }
    76  
    77  func (v v2_0CommandRequest) CommandToBeAuthorized() string {
    78  	return v.ReqData.Command
    79  }
    80  
    81  func (v v2_0CommandRequest) Data() ([]byte, error) {
    82  	return json.Marshal(v.ReqData)
    83  }
    84  
    85  func (v v2_0CommandRequest) RequestType() eaconst.RequestType {
    86  	return eaconst.Command
    87  }
    88  
    89  func (v v2_0CommandRequest) validate() error {
    90  	var err error
    91  	var apiErr error
    92  	if v.ReqData.Command == "" {
    93  		apiErr = apierror.E(apierror.ErrInvalidCommand, "No command identified")
    94  		err = errors.Join(err, errors.New("command is empty"))
    95  	}
    96  	if attrErr := validateAttributes(v.ReqAttr, string(eaconst.MessageVersion2_0), string(eaconst.Command)); attrErr != nil {
    97  		err = errors.Join(err, attrErr)
    98  	}
    99  	if err != nil {
   100  		return apierror.E(apierror.ErrInvalidCommand, apiErr, err)
   101  	}
   102  	return nil
   103  }
   104  
   105  func assembleV2_0CommandRequest(data []byte, attributes map[string]string) (Request, error) {
   106  	var reqData v2Command
   107  	if err := json.Unmarshal(data, &reqData); err != nil {
   108  		return nil, fmt.Errorf("failed to unmarshal data: %w", err)
   109  	}
   110  	req := v2_0CommandRequest{
   111  		ReqData: reqData,
   112  		ReqAttr: deepCopyMap(attributes),
   113  	}
   114  	if err := req.validate(); err != nil {
   115  		return nil, err
   116  	}
   117  	return req, nil
   118  }
   119  
   120  type v2_0ExecutableRequest struct {
   121  	ReqAttr map[string]string `json:"attributes"`
   122  	ReqData v2Executable      `json:"data"`
   123  }
   124  
   125  type v2Executable struct {
   126  	Executable executable `json:"executable"`
   127  	Args       []string   `json:"args"`
   128  }
   129  
   130  type executable struct {
   131  	Name     string `json:"name"`
   132  	Contents string `json:"contents"`
   133  }
   134  
   135  func (v *v2_0ExecutableRequest) AddAttribute(key, val string) {
   136  	if _, ok := v.ReqAttr[key]; !ok {
   137  		v.ReqAttr[key] = val
   138  	}
   139  }
   140  
   141  func (v *v2_0ExecutableRequest) Attributes() map[string]string {
   142  	return deepCopyMap(v.ReqAttr)
   143  }
   144  
   145  func (v *v2_0ExecutableRequest) CommandToBeAuthorized() string {
   146  	return v.ReqData.Executable.Name
   147  }
   148  
   149  func (v *v2_0ExecutableRequest) Data() ([]byte, error) {
   150  	return json.Marshal(v.ReqData)
   151  }
   152  
   153  func (v *v2_0ExecutableRequest) RequestType() eaconst.RequestType {
   154  	return eaconst.Executable
   155  }
   156  
   157  func (v *v2_0ExecutableRequest) WriteContents(contents string) {
   158  	v.ReqData.Executable.Contents = contents
   159  }
   160  
   161  func (v v2_0ExecutableRequest) validate() error {
   162  	var err error
   163  	var apiErr error
   164  	if v.ReqData.Executable.Name == "" {
   165  		apiErr = apierror.E(apierror.ErrInvalidCommand, "No executable name identified")
   166  		err = errors.Join(err, errors.New("executable name is empty"))
   167  	}
   168  	if attrErr := validateAttributes(v.ReqAttr, string(eaconst.MessageVersion2_0), string(eaconst.Executable)); attrErr != nil {
   169  		err = errors.Join(err, attrErr)
   170  	}
   171  	if err != nil {
   172  		return apierror.E(apierror.ErrInvalidCommand, apiErr, err)
   173  	}
   174  	return nil
   175  }
   176  
   177  func assembleV2_0ExecutableRequest(data []byte, attributes map[string]string) (Request, error) {
   178  	var reqData v2Executable
   179  	if err := json.Unmarshal(data, &reqData); err != nil {
   180  		return nil, fmt.Errorf("failed to unmarshal data: %w", err)
   181  	}
   182  	req := v2_0ExecutableRequest{
   183  		ReqData: reqData,
   184  		ReqAttr: deepCopyMap(attributes),
   185  	}
   186  	if err := req.validate(); err != nil {
   187  		return nil, err
   188  	}
   189  	return &req, nil
   190  }
   191  

View as plain text