Repository: cloudflare/cloudflare-go (go)

Issue:
List Certificates function for Per-hostname Authenticated Origin Pull missing
### Current cloudflare-go version

v0.16.0

### Description

The cloudflare has a `List Certificates` call for Per-hostname Authenticated Origin Pulls. 
This is missing from the current cloudflare-go inplementation

### Use cases

This would mirror the cloudflare API.

Would allow a get of  list of certificates for a hostname on a zone 

### Potential cloudflare-go usage

```go
func (api *API) ListPerHostnameAuthenticatedOriginPullsCertificate(ctx context.Context, zoneID string) (PerHostnameAuthenticatedOriginPullsCertificateDetails, error) {
	uri := fmt.Sprintf("/zones/%s/origin_tls_client_auth/hostnames/certificates", zoneID)
	res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
	if err != nil {
		return PerHostnameAuthenticatedOriginPullsCertificateDetails{}, err
	}
	var r PerHostnameAuthenticatedOriginPullsCertificateResponse
	if err := json.Unmarshal(res, &r); err != nil {
		return PerHostnameAuthenticatedOriginPullsCertificateDetails{}, errors.Wrap(err, errUnmarshalError)
	}
	return r.Result, nil
}
```


### References

_No response_

Pull request description:
Add List Certificates function for Per-hostname Authenticated Origin pull
Description
Add List Certificates function for Per-hostname Authenticated Origin pull to mirror cloudflare api with tests

Has your change been tested?
Added tests

Types of changes
What sort of change does your code introduce/modify?

New feature (non-breaking change which adds functionality)

Checklist:
[ X] My code follows the code style of this project.
[ X] My change requires a change to the documentation.
[ X] I have updated the documentation accordingly.
[ X] I have added tests to cover my changes.
[ X] All new and existing tests passed.
resolves #631

Patch:
diff --git a/authenticated_origin_pulls_per_hostname.go b/authenticated_origin_pulls_per_hostname.go
index 7606d6560..4242e0754 100644
--- a/authenticated_origin_pulls_per_hostname.go
+++ b/authenticated_origin_pulls_per_hostname.go
@@ -76,6 +76,22 @@ type PerHostnameAuthenticatedOriginPullsConfigParams struct {
 	Config []PerHostnameAuthenticatedOriginPullsConfig `json:"config"`
 }
 
+// ListPerHostnameAuthenticatedOriginPullsCertificates will get all certificate under Per Hostname AuthenticatedOriginPulls zone.
+//
+// API reference: https://api.cloudflare.com/#per-hostname-authenticated-origin-pull-list-certificates
+func (api *API) ListPerHostnameAuthenticatedOriginPullsCertificates(ctx context.Context, zoneID string) ([]PerHostnameAuthenticatedOriginPullsDetails, error) {
+	uri := fmt.Sprintf("/zones/%s/origin_tls_client_auth/hostnames/certificates", zoneID)
+	res, err := api.makeRequestContext(ctx, http.MethodGet, uri, nil)
+	if err != nil {
+		return []PerHostnameAuthenticatedOriginPullsDetails{}, err
+	}
+	var r PerHostnamesAuthenticatedOriginPullsDetailsResponse
+	if err := json.Unmarshal(res, &r); err != nil {
+		return []PerHostnameAuthenticatedOriginPullsDetails{}, errors.Wrap(err, errUnmarshalError)
+	}
+	return r.Result, nil
+}
+
 // UploadPerHostnameAuthenticatedOriginPullsCertificate will upload the provided certificate and private key to the edge under Per Hostname AuthenticatedOriginPulls.
 //
 // API reference: https://api.cloudflare.com/#per-hostname-authenticated-origin-pull-upload-a-hostname-client-certificate


Test patch:
diff --git a/authenticated_origin_pulls_per_hostname_test.go b/authenticated_origin_pulls_per_hostname_test.go
index dc7811d21..635ceb101 100644
--- a/authenticated_origin_pulls_per_hostname_test.go
+++ b/authenticated_origin_pulls_per_hostname_test.go
@@ -10,6 +10,97 @@ import (
 	"github.com/stretchr/testify/assert"
 )
 
+func TestListPerHostnameAuthenticatedOriginPullsCertificate(t *testing.T) {
+	setup()
+	defer teardown()
+
+	handler := func(w http.ResponseWriter, r *http.Request) {
+		w.Header().Set("content-type", "application/json")
+		fmt.Fprint(w, `{
+			"success": true,
+			"errors": [],
+			"messages": [],
+			"result": [
+				{
+					"hostname": "app.example.com",
+					"cert_id": "2458ce5a-0c35-4c7f-82c7-8e9487d3ff60",
+					"enabled": true,
+					"status": "active",
+					"created_at": "2019-10-28T18:11:23.37411Z",
+					"updated_at": "2019-10-28T18:11:23.37411Z",
+					"cert_status": "active",
+					"issuer": "GlobalSign",
+					"signature": "SHA256WithRSA",
+					"serial_number": "6743787633689793699141714808227354901",
+					"certificate": "-----BEGIN CERTIFICATE-----\nMIIDtTCCAp2gAwIBAgIJAMHAwfXZ5/PWMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV\nBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX\naWRnaXRzIFB0eSBMdGQwHhcNMTYwODI0MTY0MzAxWhcNMTYxMTIyMTY0MzAxWjBF\nMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50\nZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\nCgKCAQEAwQHoetcl9+5ikGzV6cMzWtWPJHqXT3wpbEkRU9Yz7lgvddmGdtcGbg/1\nCGZu0jJGkMoppoUo4c3dts3iwqRYmBikUP77wwY2QGmDZw2FvkJCJlKnabIRuGvB\nKwzESIXgKk2016aTP6/dAjEHyo6SeoK8lkIySUvK0fyOVlsiEsCmOpidtnKX/a+5\n0GjB79CJH4ER2lLVZnhePFR/zUOyPxZQQ4naHf7yu/b5jhO0f8fwt+pyFxIXjbEI\ndZliWRkRMtzrHOJIhrmJ2A1J7iOrirbbwillwjjNVUWPf3IJ3M12S9pEewooaeO2\nizNTERcG9HzAacbVRn2Y2SWIyT/18QIDAQABo4GnMIGkMB0GA1UdDgQWBBT/LbE4\n9rWf288N6sJA5BRb6FJIGDB1BgNVHSMEbjBsgBT/LbE49rWf288N6sJA5BRb6FJI\nGKFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNV\nBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAMHAwfXZ5/PWMAwGA1UdEwQF\nMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAHHFwl0tH0quUYZYO0dZYt4R7SJ0pCm2\n2satiyzHl4OnXcHDpekAo7/a09c6Lz6AU83cKy/+x3/djYHXWba7HpEu0dR3ugQP\nMlr4zrhd9xKZ0KZKiYmtJH+ak4OM4L3FbT0owUZPyjLSlhMtJVcoRp5CJsjAMBUG\nSvD8RX+T01wzox/Qb+lnnNnOlaWpqu8eoOenybxKp1a9ULzIVvN/LAcc+14vioFq\n2swRWtmocBAs8QR9n4uvbpiYvS8eYueDCWMM4fvFfBhaDZ3N9IbtySh3SpFdQDhw\nYbjM2rxXiyLGxB4Bol7QTv4zHif7Zt89FReT/NBy4rzaskDJY5L6xmY=\n-----END CERTIFICATE-----\n",
+					"cert_uploaded_on": "2019-10-28T18:11:23.37411Z",
+					"cert_updated_at": "2019-10-28T18:11:23.37411Z",
+					"expires_on": "2100-01-01T05:20:00Z"
+				},
+				{
+					"hostname": "anotherapp.example.com",
+					"cert_id": "2458ce5a-0c35-4c7f-82c7-8e9487d3ff61",
+					"enabled": true,
+					"status": "active",
+					"created_at": "2019-10-28T18:11:23.37411Z",
+					"updated_at": "2019-10-28T18:11:23.37411Z",
+					"cert_status": "active",
+					"issuer": "GlobalSign",
+					"signature": "SHA256WithRSA",
+					"serial_number": "6743787633689793699141714808227354921",
+					"certificate": "-----BEGIN CERTIFICATE-----\nMIIDtTCCAp2gAwIBAgIJAMHAwfXZ5/PWMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV\nBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX\naWRnaXRzIFB0eSBMdGQwHhcNMTYwODI0MTY0MzAxWhcNMTYxMTIyMTY0MzAxWjBF\nMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50\nZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\nCgKCAQEAwQHoetcl9+5ikGzV6cMzWtWPJHqXT3wpbEkRU9Yz7lgvddmGdtcGbg/1\nCGZu0jJGkMoppoUo4c3dts3iwqRYmBikUP77wwY2QGmDZw2FvkJCJlKnabIRuGvB\nKwzESIXgKk2016aTP6/dAjEHyo6SeoK8lkIySUvK0fyOVlsiEsCmOpidtnKX/a+5\n0GjB79CJH4ER2lLVZnhePFR/zUOyPxZQQ4naHf7yu/b5jhO0f8fwt+pyFxIXjbEI\ndZliWRkRMtzrHOJIhrmJ2A1J7iOrirbbwillwjjNVUWPf3IJ3M12S9pEewooaeO2\nizNTERcG9HzAacbVRn2Y2SWIyT/18QIDAQABo4GnMIGkMB0GA1UdDgQWBBT/LbE4\n9rWf288N6sJA5BRb6FJIGDB1BgNVHSMEbjBsgBT/LbE49rWf288N6sJA5BRb6FJI\nGKFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNV\nBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAMHAwfXZ5/PWMAwGA1UdEwQF\nMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAHHFwl0tH0quUYZYO0dZYt4R7SJ0pCm2\n2satiyzHl4OnXcHDpekAo7/a09c6Lz6AU83cKy/+x3/djYHXWba7HpEu0dR3ugQP\nMlr4zrhd9xKZ0KZKiYmtJH+ak4OM4L3FbT0owUZPyjLSlhMtJVcoRp5CJsjAMBUG\nSvD8RX+T01wzox/Qb+lnnNnOlaWpqu8eoOenybxKp1a9ULzIVvN/LAcc+14vioFq\n2swRWtmocBAs8QR9n4uvbpiYvS8eYueDCWMM4fvFfBhaDZ3N9IbtySh3SpFdQDhw\nYbjM2rxXiyLGxB4Bol7QTv4zHif7Zt89FReT/NBy4rzaskDJY5L6xmY=\n-----END CERTIFICATE-----\n",
+					"cert_uploaded_on": "2019-10-28T18:11:23.37411Z",
+					"cert_updated_at": "2019-10-28T18:11:23.37411Z",
+					"expires_on": "2100-01-01T05:20:00Z"
+				  }
+			  ]
+		}`)
+	}
+
+	mux.HandleFunc("/zones/023e105f4ecef8ad9ca31a8372d0c353/origin_tls_client_auth/hostnames/certificates", handler)
+	expiresOn, _ := time.Parse(time.RFC3339, "2100-01-01T05:20:00Z")
+	createdAt, _ := time.Parse(time.RFC3339, "2019-10-28T18:11:23.37411Z")
+	updatedAt, _ := time.Parse(time.RFC3339, "2019-10-28T18:11:23.37411Z")
+
+	want := []PerHostnameAuthenticatedOriginPullsDetails{
+		{
+			Hostname:       "app.example.com",
+			Enabled:        true,
+			CertStatus:     "active",
+			CreatedAt:      createdAt,
+			UpdatedAt:      updatedAt,
+			CertID:         "2458ce5a-0c35-4c7f-82c7-8e9487d3ff60",
+			Certificate:    "-----BEGIN CERTIFICATE-----\nMIIDtTCCAp2gAwIBAgIJAMHAwfXZ5/PWMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV\nBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX\naWRnaXRzIFB0eSBMdGQwHhcNMTYwODI0MTY0MzAxWhcNMTYxMTIyMTY0MzAxWjBF\nMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50\nZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\nCgKCAQEAwQHoetcl9+5ikGzV6cMzWtWPJHqXT3wpbEkRU9Yz7lgvddmGdtcGbg/1\nCGZu0jJGkMoppoUo4c3dts3iwqRYmBikUP77wwY2QGmDZw2FvkJCJlKnabIRuGvB\nKwzESIXgKk2016aTP6/dAjEHyo6SeoK8lkIySUvK0fyOVlsiEsCmOpidtnKX/a+5\n0GjB79CJH4ER2lLVZnhePFR/zUOyPxZQQ4naHf7yu/b5jhO0f8fwt+pyFxIXjbEI\ndZliWRkRMtzrHOJIhrmJ2A1J7iOrirbbwillwjjNVUWPf3IJ3M12S9pEewooaeO2\nizNTERcG9HzAacbVRn2Y2SWIyT/18QIDAQABo4GnMIGkMB0GA1UdDgQWBBT/LbE4\n9rWf288N6sJA5BRb6FJIGDB1BgNVHSMEbjBsgBT/LbE49rWf288N6sJA5BRb6FJI\nGKFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNV\nBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAMHAwfXZ5/PWMAwGA1UdEwQF\nMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAHHFwl0tH0quUYZYO0dZYt4R7SJ0pCm2\n2satiyzHl4OnXcHDpekAo7/a09c6Lz6AU83cKy/+x3/djYHXWba7HpEu0dR3ugQP\nMlr4zrhd9xKZ0KZKiYmtJH+ak4OM4L3FbT0owUZPyjLSlhMtJVcoRp5CJsjAMBUG\nSvD8RX+T01wzox/Qb+lnnNnOlaWpqu8eoOenybxKp1a9ULzIVvN/LAcc+14vioFq\n2swRWtmocBAs8QR9n4uvbpiYvS8eYueDCWMM4fvFfBhaDZ3N9IbtySh3SpFdQDhw\nYbjM2rxXiyLGxB4Bol7QTv4zHif7Zt89FReT/NBy4rzaskDJY5L6xmY=\n-----END CERTIFICATE-----\n",
+			Issuer:         "GlobalSign",
+			Signature:      "SHA256WithRSA",
+			SerialNumber:   "6743787633689793699141714808227354901",
+			ExpiresOn:      expiresOn,
+			Status:         "active",
+			CertUploadedOn: updatedAt,
+			CertUpdatedAt:  updatedAt,
+		}, {
+			Hostname:       "anotherapp.example.com",
+			Enabled:        true,
+			CertStatus:     "active",
+			CreatedAt:      createdAt,
+			UpdatedAt:      updatedAt,
+			CertID:         "2458ce5a-0c35-4c7f-82c7-8e9487d3ff61",
+			Certificate:    "-----BEGIN CERTIFICATE-----\nMIIDtTCCAp2gAwIBAgIJAMHAwfXZ5/PWMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV\nBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX\naWRnaXRzIFB0eSBMdGQwHhcNMTYwODI0MTY0MzAxWhcNMTYxMTIyMTY0MzAxWjBF\nMQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50\nZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\nCgKCAQEAwQHoetcl9+5ikGzV6cMzWtWPJHqXT3wpbEkRU9Yz7lgvddmGdtcGbg/1\nCGZu0jJGkMoppoUo4c3dts3iwqRYmBikUP77wwY2QGmDZw2FvkJCJlKnabIRuGvB\nKwzESIXgKk2016aTP6/dAjEHyo6SeoK8lkIySUvK0fyOVlsiEsCmOpidtnKX/a+5\n0GjB79CJH4ER2lLVZnhePFR/zUOyPxZQQ4naHf7yu/b5jhO0f8fwt+pyFxIXjbEI\ndZliWRkRMtzrHOJIhrmJ2A1J7iOrirbbwillwjjNVUWPf3IJ3M12S9pEewooaeO2\nizNTERcG9HzAacbVRn2Y2SWIyT/18QIDAQABo4GnMIGkMB0GA1UdDgQWBBT/LbE4\n9rWf288N6sJA5BRb6FJIGDB1BgNVHSMEbjBsgBT/LbE49rWf288N6sJA5BRb6FJI\nGKFJpEcwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgTClNvbWUtU3RhdGUxITAfBgNV\nBAoTGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZIIJAMHAwfXZ5/PWMAwGA1UdEwQF\nMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAHHFwl0tH0quUYZYO0dZYt4R7SJ0pCm2\n2satiyzHl4OnXcHDpekAo7/a09c6Lz6AU83cKy/+x3/djYHXWba7HpEu0dR3ugQP\nMlr4zrhd9xKZ0KZKiYmtJH+ak4OM4L3FbT0owUZPyjLSlhMtJVcoRp5CJsjAMBUG\nSvD8RX+T01wzox/Qb+lnnNnOlaWpqu8eoOenybxKp1a9ULzIVvN/LAcc+14vioFq\n2swRWtmocBAs8QR9n4uvbpiYvS8eYueDCWMM4fvFfBhaDZ3N9IbtySh3SpFdQDhw\nYbjM2rxXiyLGxB4Bol7QTv4zHif7Zt89FReT/NBy4rzaskDJY5L6xmY=\n-----END CERTIFICATE-----\n",
+			Issuer:         "GlobalSign",
+			Signature:      "SHA256WithRSA",
+			SerialNumber:   "6743787633689793699141714808227354921",
+			ExpiresOn:      expiresOn,
+			Status:         "active",
+			CertUploadedOn: updatedAt,
+			CertUpdatedAt:  updatedAt,
+		},
+	}
+	actual, err := client.ListPerHostnameAuthenticatedOriginPullsCertificates(context.Background(), "023e105f4ecef8ad9ca31a8372d0c353")
+	if assert.NoError(t, err) {
+		assert.Equal(t, want, actual)
+	}
+}
+
 func TestUploadPerHostnameAuthenticatedOriginPullsCertificate(t *testing.T) {
 	setup()
 	defer teardown()