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  }