github.com/akamai/AkamaiOPEN-edgegrid-golang/v8@v8.1.0/pkg/cps/dv_challenges.go (about)

     1  package cps
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"net/http"
     8  	"net/url"
     9  )
    10  
    11  type (
    12  	// DVChallenges is a CPS DV challenges API interface
    13  	DVChallenges interface {
    14  		// GetChangeLetsEncryptChallenges gets detailed information about Domain Validation challenges
    15  		//
    16  		// See: https://techdocs.akamai.com/cps/reference/get-change-allowed-input-param
    17  		GetChangeLetsEncryptChallenges(context.Context, GetChangeRequest) (*DVArray, error)
    18  
    19  		// AcknowledgeDVChallenges sends acknowledgement request to CPS informing that the validation is completed
    20  		//
    21  		// See: https://techdocs.akamai.com/cps/reference/post-change-allowed-input-param
    22  		AcknowledgeDVChallenges(context.Context, AcknowledgementRequest) error
    23  	}
    24  
    25  	// DVArray is an array of DV objects
    26  	DVArray struct {
    27  		DV []DV `json:"dv"`
    28  	}
    29  
    30  	// DV is a Domain Validation entity
    31  	DV struct {
    32  		Challenges         []Challenge `json:"challenges"`
    33  		Domain             string      `json:"domain"`
    34  		Error              string      `json:"error"`
    35  		Expires            string      `json:"expires"`
    36  		RequestTimestamp   string      `json:"requestTimestamp"`
    37  		Status             string      `json:"status"`
    38  		ValidatedTimestamp string      `json:"validatedTimestamp"`
    39  		ValidationStatus   string      `json:"validationStatus"`
    40  	}
    41  
    42  	// Challenge contains domain information of a specific domain to be validated
    43  	Challenge struct {
    44  		Error             string             `json:"error"`
    45  		FullPath          string             `json:"fullPath"`
    46  		RedirectFullPath  string             `json:"redirectFullPath"`
    47  		ResponseBody      string             `json:"responseBody"`
    48  		Status            string             `json:"status"`
    49  		Token             string             `json:"token"`
    50  		Type              string             `json:"type"`
    51  		ValidationRecords []ValidationRecord `json:"validationRecords"`
    52  	}
    53  
    54  	// ValidationRecord represents validation attempt
    55  	ValidationRecord struct {
    56  		Authorities []string `json:"authorities"`
    57  		Hostname    string   `json:"hostname"`
    58  		Port        string   `json:"port"`
    59  		ResolvedIP  []string `json:"resolvedIp"`
    60  		TriedIP     string   `json:"triedIp"`
    61  		URL         string   `json:"url"`
    62  		UsedIP      string   `json:"usedIp"`
    63  	}
    64  )
    65  
    66  var (
    67  	// ErrGetChangeLetsEncryptChallenges is returned when GetChangeLetsEncryptChallenges fails
    68  	ErrGetChangeLetsEncryptChallenges = errors.New("fetching change for lets-encrypt-challenges")
    69  	// ErrAcknowledgeLetsEncryptChallenges when AcknowledgeDVChallenges fails
    70  	ErrAcknowledgeLetsEncryptChallenges = errors.New("acknowledging lets-encrypt-challenges")
    71  )
    72  
    73  func (c *cps) GetChangeLetsEncryptChallenges(ctx context.Context, params GetChangeRequest) (*DVArray, error) {
    74  	if err := params.Validate(); err != nil {
    75  		return nil, fmt.Errorf("%s: %w: %s", ErrGetChangeLetsEncryptChallenges, ErrStructValidation, err)
    76  	}
    77  
    78  	var rval DVArray
    79  
    80  	logger := c.Log(ctx)
    81  	logger.Debug("GetChangeLetsEncryptChallenges")
    82  
    83  	uri, err := url.Parse(fmt.Sprintf(
    84  		"/cps/v2/enrollments/%d/changes/%d/input/info/lets-encrypt-challenges",
    85  		params.EnrollmentID,
    86  		params.ChangeID),
    87  	)
    88  	if err != nil {
    89  		return nil, fmt.Errorf("%w: failed to parse url: %s", ErrGetChangeLetsEncryptChallenges, err)
    90  	}
    91  
    92  	req, err := http.NewRequestWithContext(ctx, http.MethodGet, uri.String(), nil)
    93  	if err != nil {
    94  		return nil, fmt.Errorf("%w: failed to create request: %s", ErrGetChangeLetsEncryptChallenges, err)
    95  	}
    96  	req.Header.Set("Accept", "application/vnd.akamai.cps.dv-challenges.v2+json")
    97  
    98  	resp, err := c.Exec(req, &rval)
    99  	if err != nil {
   100  		return nil, fmt.Errorf("%w: request failed: %s", ErrGetChangeLetsEncryptChallenges, err)
   101  	}
   102  
   103  	if resp.StatusCode != http.StatusOK {
   104  		return nil, fmt.Errorf("%s: %w", ErrGetChangeLetsEncryptChallenges, c.Error(resp))
   105  	}
   106  
   107  	return &rval, nil
   108  }
   109  
   110  func (c *cps) AcknowledgeDVChallenges(ctx context.Context, params AcknowledgementRequest) error {
   111  	if err := params.Validate(); err != nil {
   112  		return fmt.Errorf("%s: %w: %s", ErrAcknowledgeLetsEncryptChallenges, ErrStructValidation, err)
   113  	}
   114  
   115  	logger := c.Log(ctx)
   116  	logger.Debug("AcknowledgeDVVhallenges")
   117  
   118  	uri, err := url.Parse(fmt.Sprintf(
   119  		"/cps/v2/enrollments/%d/changes/%d/input/update/lets-encrypt-challenges-completed",
   120  		params.EnrollmentID, params.ChangeID))
   121  	if err != nil {
   122  		return fmt.Errorf("%w: parsing URL: %s", ErrAcknowledgeLetsEncryptChallenges, err)
   123  	}
   124  
   125  	req, err := http.NewRequestWithContext(ctx, http.MethodPost, uri.String(), nil)
   126  	if err != nil {
   127  		return fmt.Errorf("%w: failed to create request: %s", ErrAcknowledgeLetsEncryptChallenges, err)
   128  	}
   129  	req.Header.Set("Accept", "application/vnd.akamai.cps.change-id.v1+json")
   130  	req.Header.Set("Content-Type", "application/vnd.akamai.cps.acknowledgement.v1+json; charset=utf-8")
   131  
   132  	resp, err := c.Exec(req, nil, params.Acknowledgement)
   133  	if err != nil {
   134  		return fmt.Errorf("%w: request failed: %s", ErrAcknowledgeLetsEncryptChallenges, err)
   135  	}
   136  
   137  	if resp.StatusCode != http.StatusNoContent && resp.StatusCode != http.StatusAccepted && resp.StatusCode != http.StatusOK {
   138  		return fmt.Errorf("%s: %w", ErrAcknowledgeLetsEncryptChallenges, c.Error(resp))
   139  	}
   140  
   141  	return nil
   142  }