github.com/akamai/AkamaiOPEN-edgegrid-golang/v2@v2.17.0/pkg/appsec/reputation_profile.go (about) 1 package appsec 2 3 import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "net/http" 8 "reflect" 9 10 validation "github.com/go-ozzo/ozzo-validation/v4" 11 ) 12 13 type ( 14 // The ReputationProfile interface supports creating, retrieving, modifying and removing reputation 15 // profiles for a specific security configuration version. 16 // 17 // https://developer.akamai.com/api/cloud_security/application_security/v1.html#reputationprofile 18 ReputationProfile interface { 19 // https://developer.akamai.com/api/cloud_security/application_security/v1.html#getreputationprofiles 20 GetReputationProfiles(ctx context.Context, params GetReputationProfilesRequest) (*GetReputationProfilesResponse, error) 21 22 // https://developer.akamai.com/api/cloud_security/application_security/v1.html#getreputationprofile 23 GetReputationProfile(ctx context.Context, params GetReputationProfileRequest) (*GetReputationProfileResponse, error) 24 25 // https://developer.akamai.com/api/cloud_security/application_security/v1.html#postreputationprofiles 26 CreateReputationProfile(ctx context.Context, params CreateReputationProfileRequest) (*CreateReputationProfileResponse, error) 27 28 // https://developer.akamai.com/api/cloud_security/application_security/v1.html#putreputationprofile 29 UpdateReputationProfile(ctx context.Context, params UpdateReputationProfileRequest) (*UpdateReputationProfileResponse, error) 30 31 // https://developer.akamai.com/api/cloud_security/application_security/v1.html#deletereputationprofile 32 RemoveReputationProfile(ctx context.Context, params RemoveReputationProfileRequest) (*RemoveReputationProfileResponse, error) 33 } 34 35 atomicConditionsName []string 36 37 // GetReputationProfilesRequest is used to retrieve the reputation profiles for a configuration. 38 GetReputationProfilesRequest struct { 39 ConfigID int `json:"configId"` 40 ConfigVersion int `json:"configVersion"` 41 ReputationProfileId int `json:"-"` 42 } 43 44 // GetReputationProfilesResponse is returned from a call to GetReputationProfiles. 45 GetReputationProfilesResponse struct { 46 ReputationProfiles []struct { 47 Condition *ReputationProfileCondition `json:"condition,omitempty"` 48 Context string `json:"context,omitempty"` 49 ContextReadable string `json:"-"` 50 Enabled bool `json:"-"` 51 ID int `json:"id,omitempty"` 52 Name string `json:"name,omitempty"` 53 SharedIPHandling string `json:"sharedIpHandling,omitempty"` 54 Threshold int `json:"threshold,omitempty"` 55 } `json:"reputationProfiles,omitempty"` 56 } 57 58 // GetReputationProfileRequest is used to retrieve the details for a specific reputation profile. 59 GetReputationProfileRequest struct { 60 ConfigID int `json:"configId"` 61 ConfigVersion int `json:"configVersion"` 62 ReputationProfileId int `json:"-"` 63 } 64 65 // GetReputationProfileResponse is returned from a call to GetReputationProfile. 66 GetReputationProfileResponse struct { 67 Condition *GetReputationProfileResponseCondition `json:"condition,omitempty"` 68 Context string `json:"context,omitempty"` 69 ContextReadable string `json:"-"` 70 Enabled bool `json:"-"` 71 ID int `json:"-"` 72 Name string `json:"name,omitempty"` 73 SharedIPHandling string `json:"sharedIpHandling,omitempty"` 74 Threshold int `json:"threshold,omitempty"` 75 } 76 77 // CreateReputationProfileRequest is used to create a reputation profile. 78 CreateReputationProfileRequest struct { 79 ConfigID int `json:"-"` 80 ConfigVersion int `json:"-"` 81 JsonPayloadRaw json.RawMessage `json:"-"` 82 } 83 84 // CreateReputationProfileResponse is returned from a call to CreateReputationProfile. 85 CreateReputationProfileResponse struct { 86 ID int `json:"id"` 87 Name string `json:"name"` 88 Context string `json:"context"` 89 Description string `json:"description"` 90 Threshold int `json:"threshold"` 91 SharedIPHandling string `json:"sharedIpHandling"` 92 Condition struct { 93 AtomicConditions []struct { 94 CheckIps string `json:"checkIps,omitempty"` 95 ClassName string `json:"className"` 96 Index int `json:"index"` 97 PositiveMatch bool `json:"positiveMatch"` 98 Value []string `json:"value,omitempty"` 99 Name atomicConditionsName `json:"name,omitempty"` 100 NameCase bool `json:"nameCase,omitempty"` 101 NameWildcard bool `json:"nameWildcard,omitempty"` 102 ValueCase bool `json:"valueCase,omitempty"` 103 ValueWildcard bool `json:"valueWildcard,omitempty"` 104 Host []string `json:"host,omitempty"` 105 } `json:"atomicConditions"` 106 PositiveMatch *json.RawMessage `json:"positiveMatch,omitempty"` 107 } `json:"condition"` 108 Enabled bool `json:"enabled"` 109 } 110 111 // UpdateReputationProfileRequest is used to modify an existing reputation profile. 112 UpdateReputationProfileRequest struct { 113 ConfigID int `json:"-"` 114 ConfigVersion int `json:"-"` 115 ReputationProfileId int `json:"-"` 116 JsonPayloadRaw json.RawMessage `json:"-"` 117 } 118 119 // UpdateReputationProfileResponse is returned from a call to UpdateReputationProfile. 120 UpdateReputationProfileResponse struct { 121 ID int `json:"id"` 122 PolicyID int `json:"policyId"` 123 ConfigID int `json:"configId"` 124 ConfigVersion int `json:"configVersion"` 125 MatchType string `json:"matchType"` 126 Type string `json:"type"` 127 Name string `json:"name"` 128 Description string `json:"description"` 129 AverageThreshold int `json:"averageThreshold"` 130 BurstThreshold int `json:"burstThreshold"` 131 ClientIdentifier string `json:"clientIdentifier"` 132 UseXForwardForHeaders bool `json:"useXForwardForHeaders"` 133 RequestType string `json:"requestType"` 134 SameActionOnIpv6 bool `json:"sameActionOnIpv6"` 135 Path struct { 136 PositiveMatch bool `json:"positiveMatch"` 137 Values []string `json:"values"` 138 } `json:"path"` 139 PathMatchType string `json:"pathMatchType"` 140 PathURIPositiveMatch bool `json:"pathUriPositiveMatch"` 141 FileExtensions struct { 142 PositiveMatch bool `json:"positiveMatch"` 143 Values []string `json:"values"` 144 } `json:"fileExtensions"` 145 Hostnames []string `json:"hostNames"` 146 AdditionalMatchOptions []struct { 147 PositiveMatch bool `json:"positiveMatch"` 148 Type string `json:"type"` 149 Values []string `json:"values"` 150 } `json:"additionalMatchOptions"` 151 QueryParameters []struct { 152 Name string `json:"name"` 153 Values []string `json:"values"` 154 PositiveMatch bool `json:"positiveMatch"` 155 ValueInRange bool `json:"valueInRange"` 156 } `json:"queryParameters"` 157 CreateDate string `json:"createDate"` 158 UpdateDate string `json:"updateDate"` 159 Used bool `json:"used"` 160 } 161 162 // RemoveReputationProfileRequest is used to remove a reputation profile. 163 RemoveReputationProfileRequest struct { 164 ConfigID int `json:"configId"` 165 ConfigVersion int `json:"configVersion"` 166 ReputationProfileId int `json:"-"` 167 } 168 169 // RemoveReputationProfileResponse is returned from a call to RemoveReputationProfile. 170 RemoveReputationProfileResponse struct { 171 ID int `json:"id"` 172 PolicyID int `json:"policyId"` 173 ConfigID int `json:"configId"` 174 ConfigVersion int `json:"configVersion"` 175 MatchType string `json:"matchType"` 176 Type string `json:"type"` 177 Name string `json:"name"` 178 Description string `json:"description"` 179 AverageThreshold int `json:"averageThreshold"` 180 BurstThreshold int `json:"burstThreshold"` 181 ClientIdentifier string `json:"clientIdentifier"` 182 UseXForwardForHeaders bool `json:"useXForwardForHeaders"` 183 RequestType string `json:"requestType"` 184 SameActionOnIpv6 bool `json:"sameActionOnIpv6"` 185 Path struct { 186 PositiveMatch bool `json:"positiveMatch"` 187 Values []string `json:"values"` 188 } `json:"path"` 189 PathMatchType string `json:"pathMatchType"` 190 PathURIPositiveMatch bool `json:"pathUriPositiveMatch"` 191 FileExtensions struct { 192 PositiveMatch bool `json:"positiveMatch"` 193 Values []string `json:"values"` 194 } `json:"fileExtensions"` 195 Hostnames []string `json:"hostNames"` 196 AdditionalMatchOptions []struct { 197 PositiveMatch bool `json:"positiveMatch"` 198 Type string `json:"type"` 199 Values []string `json:"values"` 200 } `json:"additionalMatchOptions"` 201 QueryParameters []struct { 202 Name string `json:"name"` 203 Values []string `json:"values"` 204 PositiveMatch bool `json:"positiveMatch"` 205 ValueInRange bool `json:"valueInRange"` 206 } `json:"queryParameters"` 207 CreateDate string `json:"createDate"` 208 UpdateDate string `json:"updateDate"` 209 Used bool `json:"used"` 210 } 211 212 // ReputationProfileCondition is used as part of a reputation profile description. 213 ReputationProfileCondition struct { 214 AtomicConditions []struct { 215 CheckIps *json.RawMessage `json:"checkIps,omitempty"` 216 ClassName string `json:"className,omitempty"` 217 Index int `json:"index,omitempty"` 218 PositiveMatch *json.RawMessage `json:"positiveMatch,omitempty"` 219 Value []string `json:"value,omitempty"` 220 Name *json.RawMessage `json:"name,omitempty"` 221 NameCase bool `json:"nameCase,omitempty"` 222 NameWildcard *json.RawMessage `json:"nameWildcard,omitempty"` 223 ValueCase bool `json:"valueCase,omitempty"` 224 ValueWildcard *json.RawMessage `json:"valueWildcard,omitempty"` 225 Host []string `json:"host,omitempty"` 226 } `json:"atomicConditions,omitempty"` 227 PositiveMatch *json.RawMessage `json:"positiveMatch,omitempty"` 228 } 229 230 // GetReputationProfileResponseCondition is used as part of the response to GetReputationProfile. 231 GetReputationProfileResponseCondition struct { 232 AtomicConditions []struct { 233 CheckIps *json.RawMessage `json:"checkIps,omitempty"` 234 ClassName string `json:"className,omitempty"` 235 Index int `json:"index,omitempty"` 236 PositiveMatch json.RawMessage `json:"positiveMatch,omitempty"` 237 Value []string `json:"value,omitempty"` 238 Name *json.RawMessage `json:"name,omitempty"` 239 NameCase bool `json:"nameCase,omitempty"` 240 NameWildcard *json.RawMessage `json:"nameWildcard,omitempty"` 241 ValueCase bool `json:"valueCase,omitempty"` 242 ValueWildcard *json.RawMessage `json:"valueWildcard,omitempty"` 243 Host []string `json:"host,omitempty"` 244 } `json:"atomicConditions,omitempty"` 245 PositiveMatch *json.RawMessage `json:"positiveMatch,omitempty"` 246 } 247 ) 248 249 func (c *atomicConditionsName) UnmarshalJSON(data []byte) error { 250 var nums interface{} 251 err := json.Unmarshal(data, &nums) 252 if err != nil { 253 return err 254 } 255 256 items := reflect.ValueOf(nums) 257 switch items.Kind() { 258 case reflect.String: 259 *c = append(*c, items.String()) 260 261 case reflect.Slice: 262 *c = make(atomicConditionsName, 0, items.Len()) 263 for i := 0; i < items.Len(); i++ { 264 item := items.Index(i) 265 switch item.Kind() { 266 case reflect.String: 267 *c = append(*c, item.String()) 268 case reflect.Interface: 269 *c = append(*c, item.Interface().(string)) 270 } 271 } 272 } 273 return nil 274 } 275 276 // Validate validates a GetReputationProfileRequest. 277 func (v GetReputationProfileRequest) Validate() error { 278 return validation.Errors{ 279 "ConfigID": validation.Validate(v.ConfigID, validation.Required), 280 "ConfigVersion": validation.Validate(v.ConfigVersion, validation.Required), 281 "RatePolicyID": validation.Validate(v.ReputationProfileId, validation.Required), 282 }.Filter() 283 } 284 285 // Validate validates a GetReputationProfilesRequest. 286 func (v GetReputationProfilesRequest) Validate() error { 287 return validation.Errors{ 288 "ConfigID": validation.Validate(v.ConfigID, validation.Required), 289 "ConfigVersion": validation.Validate(v.ConfigVersion, validation.Required), 290 }.Filter() 291 } 292 293 // Validate validates a CreateReputationProfileRequest. 294 func (v CreateReputationProfileRequest) Validate() error { 295 return validation.Errors{ 296 "ConfigID": validation.Validate(v.ConfigID, validation.Required), 297 "ConfigVersion": validation.Validate(v.ConfigVersion, validation.Required), 298 }.Filter() 299 } 300 301 // Validate validates an UpdateReputationProfileRequest. 302 func (v UpdateReputationProfileRequest) Validate() error { 303 return validation.Errors{ 304 "ConfigID": validation.Validate(v.ConfigID, validation.Required), 305 "ConfigVersion": validation.Validate(v.ConfigVersion, validation.Required), 306 "ReputationProfileId": validation.Validate(v.ReputationProfileId, validation.Required), 307 }.Filter() 308 } 309 310 // Validate validates a RemoveReputationProfileRequest. 311 func (v RemoveReputationProfileRequest) Validate() error { 312 return validation.Errors{ 313 "ConfigID": validation.Validate(v.ConfigID, validation.Required), 314 "ConfigVersion": validation.Validate(v.ConfigVersion, validation.Required), 315 "ReputationProfileId": validation.Validate(v.ReputationProfileId, validation.Required), 316 }.Filter() 317 } 318 319 func (p *appsec) GetReputationProfile(ctx context.Context, params GetReputationProfileRequest) (*GetReputationProfileResponse, error) { 320 logger := p.Log(ctx) 321 logger.Debug("GetReputationProfile") 322 323 if err := params.Validate(); err != nil { 324 return nil, fmt.Errorf("%w: %s", ErrStructValidation, err.Error()) 325 } 326 327 uri := fmt.Sprintf( 328 "/appsec/v1/configs/%d/versions/%d/reputation-profiles/%d", 329 params.ConfigID, 330 params.ConfigVersion, 331 params.ReputationProfileId) 332 333 req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil) 334 if err != nil { 335 return nil, fmt.Errorf("failed to create GetReputationProfile request: %w", err) 336 } 337 338 var result GetReputationProfileResponse 339 resp, err := p.Exec(req, &result) 340 if err != nil { 341 return nil, fmt.Errorf("get reputation profile request failed: %w", err) 342 } 343 if resp.StatusCode != http.StatusOK { 344 return nil, p.Error(resp) 345 } 346 347 return &result, nil 348 } 349 350 func (p *appsec) GetReputationProfiles(ctx context.Context, params GetReputationProfilesRequest) (*GetReputationProfilesResponse, error) { 351 logger := p.Log(ctx) 352 logger.Debug("GetReputationProfiles") 353 354 if err := params.Validate(); err != nil { 355 return nil, fmt.Errorf("%w: %s", ErrStructValidation, err.Error()) 356 } 357 358 uri := fmt.Sprintf( 359 "/appsec/v1/configs/%d/versions/%d/reputation-profiles", 360 params.ConfigID, 361 params.ConfigVersion, 362 ) 363 364 req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri, nil) 365 if err != nil { 366 return nil, fmt.Errorf("failed to create GetReputationProfiles request: %w", err) 367 } 368 369 var result GetReputationProfilesResponse 370 resp, err := p.Exec(req, &result) 371 if err != nil { 372 return nil, fmt.Errorf("get reputation profiles request failed: %w", err) 373 } 374 if resp.StatusCode != http.StatusOK { 375 return nil, p.Error(resp) 376 } 377 378 if params.ReputationProfileId != 0 { 379 var filteredResult GetReputationProfilesResponse 380 for _, val := range result.ReputationProfiles { 381 if val.ID == params.ReputationProfileId { 382 filteredResult.ReputationProfiles = append(filteredResult.ReputationProfiles, val) 383 } 384 } 385 return &filteredResult, nil 386 } 387 388 return &result, nil 389 } 390 391 func (p *appsec) UpdateReputationProfile(ctx context.Context, params UpdateReputationProfileRequest) (*UpdateReputationProfileResponse, error) { 392 logger := p.Log(ctx) 393 logger.Debug("UpdateReputationProfile") 394 395 if err := params.Validate(); err != nil { 396 return nil, fmt.Errorf("%w: %s", ErrStructValidation, err.Error()) 397 } 398 399 uri := fmt.Sprintf( 400 "/appsec/v1/configs/%d/versions/%d/reputation-profiles/%d", 401 params.ConfigID, 402 params.ConfigVersion, 403 params.ReputationProfileId, 404 ) 405 406 req, err := http.NewRequestWithContext(ctx, http.MethodPut, uri, nil) 407 if err != nil { 408 return nil, fmt.Errorf("failed to create UpdateReputationProfile request: %w", err) 409 } 410 req.Header.Set("Content-Type", "application/json") 411 412 var result UpdateReputationProfileResponse 413 resp, err := p.Exec(req, &result, params.JsonPayloadRaw) 414 if err != nil { 415 return nil, fmt.Errorf("update reputation profile request failed: %w", err) 416 } 417 if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated { 418 return nil, p.Error(resp) 419 } 420 421 return &result, nil 422 } 423 424 func (p *appsec) CreateReputationProfile(ctx context.Context, params CreateReputationProfileRequest) (*CreateReputationProfileResponse, error) { 425 logger := p.Log(ctx) 426 logger.Debug("CreateReputationProfile") 427 428 if err := params.Validate(); err != nil { 429 return nil, fmt.Errorf("%w: %s", ErrStructValidation, err.Error()) 430 } 431 432 uri := fmt.Sprintf( 433 "/appsec/v1/configs/%d/versions/%d/reputation-profiles", 434 params.ConfigID, 435 params.ConfigVersion, 436 ) 437 438 req, err := http.NewRequestWithContext(ctx, http.MethodPost, uri, nil) 439 if err != nil { 440 return nil, fmt.Errorf("failed to create CreateReputationProfile request: %w", err) 441 } 442 443 var result CreateReputationProfileResponse 444 req.Header.Set("Content-Type", "application/json") 445 resp, err := p.Exec(req, &result, params.JsonPayloadRaw) 446 if err != nil { 447 return nil, fmt.Errorf("create reputation profile request failed: %w", err) 448 } 449 if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusCreated { 450 return nil, p.Error(resp) 451 } 452 453 return &result, nil 454 } 455 456 func (p *appsec) RemoveReputationProfile(ctx context.Context, params RemoveReputationProfileRequest) (*RemoveReputationProfileResponse, error) { 457 logger := p.Log(ctx) 458 logger.Debug("RemoveReputationProfile") 459 460 if err := params.Validate(); err != nil { 461 return nil, fmt.Errorf("%w: %s", ErrStructValidation, err.Error()) 462 } 463 464 uri := fmt.Sprintf("/appsec/v1/configs/%d/versions/%d/reputation-profiles/%d", params.ConfigID, params.ConfigVersion, params.ReputationProfileId) 465 req, err := http.NewRequestWithContext(ctx, http.MethodDelete, uri, nil) 466 if err != nil { 467 return nil, fmt.Errorf("failed to create RemoveReputationProfile request: %w", err) 468 } 469 470 var result RemoveReputationProfileResponse 471 resp, err := p.Exec(req, &result) 472 if err != nil { 473 return nil, fmt.Errorf("remove reputation profile request failed: %w", err) 474 } 475 if resp.StatusCode != http.StatusNoContent && resp.StatusCode != http.StatusOK { 476 return nil, p.Error(resp) 477 } 478 479 return &result, nil 480 }