github.com/akamai/AkamaiOPEN-edgegrid-golang/v8@v8.1.0/pkg/appsec/match_target.go (about) 1 package appsec 2 3 import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "net/http" 8 9 validation "github.com/go-ozzo/ozzo-validation/v4" 10 ) 11 12 type ( 13 // The MatchTarget interface supports creating, retrieving, updating and removing match targets. 14 MatchTarget interface { 15 // GetMatchTargets returns match targets defined in the specified security configuration version. 16 // 17 // See: https://techdocs.akamai.com/application-security/reference/get-match-targets 18 GetMatchTargets(ctx context.Context, params GetMatchTargetsRequest) (*GetMatchTargetsResponse, error) 19 20 // GetMatchTarget returns the specified match target. 21 // 22 // See: https://techdocs.akamai.com/application-security/reference/get-match-target 23 GetMatchTarget(ctx context.Context, params GetMatchTargetRequest) (*GetMatchTargetResponse, error) 24 25 // CreateMatchTarget creates a new match target in the specified configuration version. 26 // 27 // See: https://techdocs.akamai.com/application-security/reference/post-match-targets 28 CreateMatchTarget(ctx context.Context, params CreateMatchTargetRequest) (*CreateMatchTargetResponse, error) 29 30 // UpdateMatchTarget updates details about the specified match target. 31 // 32 // See: https://techdocs.akamai.com/application-security/reference/put-match-target 33 UpdateMatchTarget(ctx context.Context, params UpdateMatchTargetRequest) (*UpdateMatchTargetResponse, error) 34 35 // RemoveMatchTarget deletes the specified match target. 36 // 37 // See: https://techdocs.akamai.com/application-security/reference/delete-match-target 38 RemoveMatchTarget(ctx context.Context, params RemoveMatchTargetRequest) (*RemoveMatchTargetResponse, error) 39 } 40 41 // GetMatchTargetsRequest is used to retrieve the match targets for a configuration. 42 GetMatchTargetsRequest struct { 43 ConfigID int `json:"configId"` 44 ConfigVersion int `json:"configVersion"` 45 TargetID int `json:"targetId"` 46 } 47 48 // GetMatchTargetsResponse is returned from a call to GetMatchTargets. 49 GetMatchTargetsResponse struct { 50 MatchTargets struct { 51 APITargets []struct { 52 Type string `json:"type,omitempty"` 53 Apis []struct { 54 ID int `json:"id"` 55 Name string `json:"name"` 56 } `json:"apis"` 57 Sequence int `json:"sequence"` 58 TargetID int `json:"targetId"` 59 ConfigID int `json:"configId,omitempty"` 60 ConfigVersion int `json:"configVersion,omitempty"` 61 62 SecurityPolicy struct { 63 PolicyID string `json:"policyId,omitempty"` 64 } `json:"securityPolicy,omitempty"` 65 66 BypassNetworkLists []struct { 67 Name string `json:"name,omitempty"` 68 ID string `json:"id,omitempty"` 69 } `json:"bypassNetworkLists,omitempty"` 70 } `json:"apiTargets,omitempty"` 71 WebsiteTargets []struct { 72 ConfigID int `json:"configId,omitempty"` 73 ConfigVersion int `json:"configVersion,omitempty"` 74 DefaultFile string `json:"defaultFile,omitempty"` 75 IsNegativeFileExtensionMatch bool `json:"isNegativeFileExtensionMatch,omitempty"` 76 IsNegativePathMatch *json.RawMessage `json:"isNegativePathMatch,omitempty"` 77 Sequence int `json:"-"` 78 TargetID int `json:"targetId,omitempty"` 79 Type string `json:"type,omitempty"` 80 FileExtensions []string `json:"fileExtensions,omitempty"` 81 FilePaths []string `json:"filePaths,omitempty"` 82 Hostnames []string `json:"hostnames,omitempty"` 83 SecurityPolicy struct { 84 PolicyID string `json:"policyId,omitempty"` 85 } `json:"securityPolicy,omitempty"` 86 BypassNetworkLists []struct { 87 Name string `json:"name,omitempty"` 88 ID string `json:"id,omitempty"` 89 } `json:"bypassNetworkLists,omitempty"` 90 } `json:"websiteTargets,omitempty"` 91 } `json:"matchTargets,omitempty"` 92 } 93 94 // GetMatchTargetRequest is used to retrieve a match target. 95 GetMatchTargetRequest struct { 96 ConfigID int `json:"configId"` 97 ConfigVersion int `json:"configVersion"` 98 TargetID int `json:"targetId"` 99 } 100 101 // GetMatchTargetResponse is returned from a call to GetMatchTarget. 102 GetMatchTargetResponse struct { 103 Type string `json:"type,omitempty"` 104 Apis []struct { 105 ID int `json:"id"` 106 Name string `json:"name"` 107 } `json:"apis,omitempty"` 108 DefaultFile string `json:"defaultFile,omitempty"` 109 Hostnames []string `json:"hostnames,omitempty"` 110 IsNegativeFileExtensionMatch bool `json:"isNegativeFileExtensionMatch,omitempty"` 111 IsNegativePathMatch *json.RawMessage `json:"isNegativePathMatch,omitempty"` 112 FilePaths []string `json:"filePaths,omitempty"` 113 FileExtensions []string `json:"fileExtensions,omitempty"` 114 SecurityPolicy struct { 115 PolicyID string `json:"policyId,omitempty"` 116 } `json:"securityPolicy,omitempty"` 117 Sequence int `json:"-"` 118 TargetID int `json:"targetId"` 119 BypassNetworkLists []struct { 120 Name string `json:"name,omitempty"` 121 ID string `json:"id,omitempty"` 122 } `json:"bypassNetworkLists,omitempty"` 123 } 124 125 // CreateMatchTargetRequest is used to create a match target. 126 CreateMatchTargetRequest struct { 127 Type string `json:"type"` 128 ConfigID int `json:"configId"` 129 ConfigVersion int `json:"configVersion"` 130 JsonPayloadRaw json.RawMessage `json:"-"` 131 } 132 133 // CreateMatchTargetResponse is returned from a call to CreateMatchTarget. 134 CreateMatchTargetResponse struct { 135 MType string `json:"type"` 136 Apis []struct { 137 ID int `json:"id"` 138 Name string `json:"name"` 139 } `json:"apis,omitempty"` 140 DefaultFile string `json:"defaultFile"` 141 Hostnames []string `json:"hostnames"` 142 IsNegativeFileExtensionMatch bool `json:"isNegativeFileExtensionMatch"` 143 IsNegativePathMatch *json.RawMessage `json:"isNegativePathMatch,omitempty"` 144 FilePaths []string `json:"filePaths"` 145 FileExtensions []string `json:"fileExtensions"` 146 SecurityPolicy struct { 147 PolicyID string `json:"policyId"` 148 } `json:"securityPolicy"` 149 Sequence int `json:"-"` 150 TargetID int `json:"targetId"` 151 BypassNetworkLists []struct { 152 Name string `json:"name"` 153 ID string `json:"id"` 154 } `json:"bypassNetworkLists"` 155 } 156 157 // UpdateMatchTargetRequest is used to modify an existing match target. 158 UpdateMatchTargetRequest struct { 159 ConfigID int `json:"configId"` 160 ConfigVersion int `json:"configVersion"` 161 JsonPayloadRaw json.RawMessage `json:"-"` 162 TargetID int `json:"targetId"` 163 } 164 165 // UpdateMatchTargetResponse is returned from a call to UpdateMatchTarget. 166 UpdateMatchTargetResponse struct { 167 Type string `json:"type"` 168 ConfigID int `json:"configId"` 169 ConfigVersion int `json:"configVersion"` 170 DefaultFile string `json:"defaultFile"` 171 Hostnames []string `json:"hostnames"` 172 IsNegativeFileExtensionMatch bool `json:"isNegativeFileExtensionMatch"` 173 IsNegativePathMatch *json.RawMessage `json:"isNegativePathMatch,omitempty"` 174 FilePaths []string `json:"filePaths"` 175 FileExtensions []string `json:"fileExtensions"` 176 SecurityPolicy struct { 177 PolicyID string `json:"policyId"` 178 } `json:"securityPolicy"` 179 Sequence int `json:"-"` 180 TargetID int `json:"targetId"` 181 BypassNetworkLists []struct { 182 Name string `json:"name"` 183 ID string `json:"id"` 184 } `json:"bypassNetworkLists"` 185 } 186 187 // RemoveMatchTargetRequest is used to remove a match target. 188 RemoveMatchTargetRequest struct { 189 ConfigID int `json:"configId"` 190 ConfigVersion int `json:"configVersion"` 191 TargetID int `json:"targetId"` 192 } 193 194 // RemoveMatchTargetResponse is returned from a call to RemoveMatchTarget. 195 RemoveMatchTargetResponse struct { 196 Type string `json:"type"` 197 ConfigID int `json:"configId"` 198 ConfigVersion int `json:"configVersion"` 199 DefaultFile string `json:"defaultFile"` 200 Hostnames []string `json:"hostnames"` 201 IsNegativeFileExtensionMatch bool `json:"isNegativeFileExtensionMatch"` 202 IsNegativePathMatch bool `json:"isNegativePathMatch"` 203 FilePaths []string `json:"filePaths"` 204 FileExtensions []string `json:"fileExtensions"` 205 SecurityPolicy struct { 206 PolicyID string `json:"policyId"` 207 } `json:"securityPolicy"` 208 Sequence int `json:"sequence"` 209 TargetID int `json:"targetId"` 210 BypassNetworkLists []struct { 211 Name string `json:"name"` 212 ID string `json:"id"` 213 } `json:"bypassNetworkLists"` 214 } 215 216 // BypassNetworkList describes a network list used in the bypass network lists for the specified configuration. 217 BypassNetworkList struct { 218 Name string `json:"name"` 219 ID string `json:"id"` 220 } 221 222 // Hostnames contains one or more hostnames. 223 Hostnames struct { 224 Hostnames string `json:"hostnames"` 225 } 226 227 // AutoGenerated is currently unused. 228 AutoGenerated struct { 229 Type string `json:"type"` 230 Apis []struct { 231 ID int `json:"id"` 232 Name string `json:"name"` 233 } `json:"apis"` 234 BypassNetworkLists []struct { 235 ID string `json:"id"` 236 Name string `json:"name"` 237 } `json:"bypassNetworkLists"` 238 ConfigID int `json:"configId"` 239 ConfigVersion int `json:"configVersion"` 240 SecurityPolicy struct { 241 PolicyID string `json:"policyId"` 242 } `json:"securityPolicy"` 243 Sequence int `json:"-"` 244 TargetID int `json:"targetId"` 245 } 246 ) 247 248 // Validate validates a GetMatchTargetRequest. 249 func (v GetMatchTargetRequest) Validate() error { 250 return validation.Errors{ 251 "ConfigID": validation.Validate(v.ConfigID, validation.Required), 252 "ConfigVersion": validation.Validate(v.ConfigVersion, validation.Required), 253 "TargetID": validation.Validate(v.TargetID, validation.Required), 254 }.Filter() 255 } 256 257 // Validate validates a GetMatchTargetsRequest. 258 func (v GetMatchTargetsRequest) Validate() error { 259 return validation.Errors{ 260 "ConfigID": validation.Validate(v.ConfigID, validation.Required), 261 "ConfigVersion": validation.Validate(v.ConfigVersion, validation.Required), 262 }.Filter() 263 } 264 265 // Validate validates a CreateMatchTargetRequest. 266 func (v CreateMatchTargetRequest) Validate() error { 267 return validation.Errors{ 268 "ConfigID": validation.Validate(v.ConfigID, validation.Required), 269 "ConfigVersion": validation.Validate(v.ConfigVersion, validation.Required), 270 }.Filter() 271 } 272 273 // Validate validates an UpdateMatchTargetRequest. 274 func (v UpdateMatchTargetRequest) Validate() error { 275 return validation.Errors{ 276 "ConfigID": validation.Validate(v.ConfigID, validation.Required), 277 "ConfigVersion": validation.Validate(v.ConfigVersion, validation.Required), 278 "TargetID": validation.Validate(v.TargetID, validation.Required), 279 }.Filter() 280 } 281 282 // Validate validates a RemoveMatchTargetRequest. 283 func (v RemoveMatchTargetRequest) Validate() error { 284 return validation.Errors{ 285 "ConfigID": validation.Validate(v.ConfigID, validation.Required), 286 "ConfigVersion": validation.Validate(v.ConfigVersion, validation.Required), 287 "TargetID": validation.Validate(v.TargetID, validation.Required), 288 }.Filter() 289 } 290 291 func (p *appsec) GetMatchTarget(ctx context.Context, params GetMatchTargetRequest) (*GetMatchTargetResponse, error) { 292 logger := p.Log(ctx) 293 logger.Debug("GetMatchTarget") 294 295 if err := params.Validate(); err != nil { 296 return nil, fmt.Errorf("%w: %s", ErrStructValidation, err.Error()) 297 } 298 299 uri := fmt.Sprintf( 300 "/appsec/v1/configs/%d/versions/%d/match-targets/%d?includeChildObjectName=true", 301 params.ConfigID, 302 params.ConfigVersion, 303 params.TargetID, 304 ) 305 306 req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil) 307 if err != nil { 308 return nil, fmt.Errorf("failed to create GetMatchTarget request: %w", err) 309 } 310 311 var result GetMatchTargetResponse 312 resp, err := p.Exec(req, &result) 313 if err != nil { 314 return nil, fmt.Errorf("get match target request failed: %w", err) 315 } 316 if resp.StatusCode != http.StatusOK { 317 return nil, p.Error(resp) 318 } 319 320 return &result, nil 321 } 322 323 func (p *appsec) GetMatchTargets(ctx context.Context, params GetMatchTargetsRequest) (*GetMatchTargetsResponse, error) { 324 logger := p.Log(ctx) 325 logger.Debug("GetMatchTargets") 326 327 if err := params.Validate(); err != nil { 328 return nil, fmt.Errorf("%w: %s", ErrStructValidation, err.Error()) 329 } 330 331 uri := fmt.Sprintf( 332 "/appsec/v1/configs/%d/versions/%d/match-targets", 333 params.ConfigID, 334 params.ConfigVersion, 335 ) 336 337 req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil) 338 if err != nil { 339 return nil, fmt.Errorf("failed to create GetMatchTargets request: %w", err) 340 } 341 342 var result GetMatchTargetsResponse 343 resp, err := p.Exec(req, &result) 344 if err != nil { 345 return nil, fmt.Errorf("get match targets request failed: %w", err) 346 } 347 if resp.StatusCode != http.StatusOK { 348 return nil, p.Error(resp) 349 } 350 351 if params.TargetID != 0 { 352 var filteredResult GetMatchTargetsResponse 353 for _, val := range result.MatchTargets.WebsiteTargets { 354 if val.TargetID == params.TargetID { 355 filteredResult.MatchTargets.WebsiteTargets = append(filteredResult.MatchTargets.WebsiteTargets, val) 356 } 357 } 358 for _, val := range result.MatchTargets.APITargets { 359 if val.TargetID == params.TargetID { 360 filteredResult.MatchTargets.APITargets = append(filteredResult.MatchTargets.APITargets, val) 361 } 362 } 363 return &filteredResult, nil 364 } 365 366 return &result, nil 367 } 368 369 func (p *appsec) UpdateMatchTarget(ctx context.Context, params UpdateMatchTargetRequest) (*UpdateMatchTargetResponse, error) { 370 logger := p.Log(ctx) 371 logger.Debug("UpdateMatchTarget") 372 373 if err := params.Validate(); err != nil { 374 return nil, fmt.Errorf("%w: %s", ErrStructValidation, err.Error()) 375 } 376 377 uri := fmt.Sprintf( 378 "/appsec/v1/configs/%d/versions/%d/match-targets/%d", 379 params.ConfigID, 380 params.ConfigVersion, 381 params.TargetID, 382 ) 383 384 req, err := http.NewRequestWithContext(ctx, http.MethodPut, uri, nil) 385 if err != nil { 386 return nil, fmt.Errorf("failed to create UpdateMatchTarget request: %w", err) 387 } 388 389 var result UpdateMatchTargetResponse 390 req.Header.Set("Content-Type", "application/json") 391 resp, err := p.Exec(req, &result, params.JsonPayloadRaw) 392 if err != nil { 393 return nil, fmt.Errorf("update match target request failed: %w", err) 394 } 395 if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated { 396 return nil, p.Error(resp) 397 } 398 399 return &result, nil 400 } 401 402 func (p *appsec) CreateMatchTarget(ctx context.Context, params CreateMatchTargetRequest) (*CreateMatchTargetResponse, error) { 403 logger := p.Log(ctx) 404 logger.Debug("CreateMatchTarget") 405 406 if err := params.Validate(); err != nil { 407 return nil, fmt.Errorf("%w: %s", ErrStructValidation, err.Error()) 408 } 409 410 uri := fmt.Sprintf( 411 "/appsec/v1/configs/%d/versions/%d/match-targets", 412 params.ConfigID, 413 params.ConfigVersion, 414 ) 415 416 req, err := http.NewRequestWithContext(ctx, http.MethodPost, uri, nil) 417 if err != nil { 418 return nil, fmt.Errorf("failed to create CreateMatchTarget request: %w", err) 419 } 420 421 var result CreateMatchTargetResponse 422 req.Header.Set("Content-Type", "application/json") 423 resp, err := p.Exec(req, &result, params.JsonPayloadRaw) 424 if err != nil { 425 return nil, fmt.Errorf("create match target request failed: %w", err) 426 } 427 if resp.StatusCode != http.StatusCreated && resp.StatusCode != http.StatusOK { 428 return nil, p.Error(resp) 429 } 430 431 return &result, nil 432 } 433 434 func (p *appsec) RemoveMatchTarget(ctx context.Context, params RemoveMatchTargetRequest) (*RemoveMatchTargetResponse, error) { 435 logger := p.Log(ctx) 436 logger.Debug("RemoveMatchTarget") 437 438 if err := params.Validate(); err != nil { 439 return nil, fmt.Errorf("%w: %s", ErrStructValidation, err.Error()) 440 } 441 442 uri := fmt.Sprintf("/appsec/v1/configs/%d/versions/%d/match-targets/%d", params.ConfigID, params.ConfigVersion, params.TargetID) 443 req, err := http.NewRequestWithContext(ctx, http.MethodDelete, uri, nil) 444 if err != nil { 445 return nil, fmt.Errorf("failed to create RemoveMatchTarget request: %w", err) 446 } 447 448 var result RemoveMatchTargetResponse 449 resp, errd := p.Exec(req, nil) 450 if errd != nil { 451 return nil, fmt.Errorf("remove match target request failed: %w", err) 452 } 453 454 if resp.StatusCode != http.StatusNoContent && resp.StatusCode != http.StatusOK { 455 return nil, p.Error(resp) 456 } 457 458 return &result, nil 459 }