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
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
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