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  }