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