diff --git a/certificate/certificates.go b/certificate/certificates.go index b0327d5c..79765e71 100644 --- a/certificate/certificates.go +++ b/certificate/certificates.go @@ -464,6 +464,33 @@ func (c *Certifier) GetOCSP(bundle []byte) ([]byte, *ocsp.Response, error) { return ocspResBytes, ocspRes, nil } +// Get attempts to fetch the certificate at the supplied URL. +// The URL is the same as what would normally be supplied at the Resource's CertURL. +// +// The returned Resource will not have the PrivateKey and CSR fields populated as these will not be available. +// +// If bundle is true, the Certificate field in the returned Resource includes the issuer certificate. +func (c *Certifier) Get(url string, bundle bool) (*Resource, error) { + cert, issuer, err := c.core.Certificates.Get(url, bundle) + if err != nil { + return nil, err + } + + // Parse the returned cert bundle so that we can grab the domain from the common name. + x509Certs, err := certcrypto.ParsePEMBundle(cert) + if err != nil { + return nil, err + } + + return &Resource{ + Domain: x509Certs[0].Subject.CommonName, + Certificate: cert, + IssuerCertificate: issuer, + CertURL: url, + CertStableURL: url, + }, nil +} + func checkOrderStatus(order acme.Order) (bool, error) { switch order.Status { case acme.StatusValid: diff --git a/certificate/certificates_test.go b/certificate/certificates_test.go index 8e8eb1d1..8ab8a51e 100644 --- a/certificate/certificates_test.go +++ b/certificate/certificates_test.go @@ -202,6 +202,38 @@ func Test_checkResponse_embeddedIssuer(t *testing.T) { assert.Equal(t, issuerMock, string(certRes.IssuerCertificate), "IssuerCertificate") } +func Test_Get(t *testing.T) { + mux, apiURL, tearDown := tester.SetupFakeAPI() + defer tearDown() + + mux.HandleFunc("/acme/cert/test-cert", func(w http.ResponseWriter, _ *http.Request) { + _, err := w.Write([]byte(certResponseMock)) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } + }) + + key, err := rsa.GenerateKey(rand.Reader, 2048) + require.NoError(t, err, "Could not generate test key") + + core, err := api.New(http.DefaultClient, "lego-test", apiURL+"/dir", "", key) + require.NoError(t, err) + + certifier := NewCertifier(core, &resolverMock{}, CertifierOptions{KeyType: certcrypto.RSA2048}) + + certRes, err := certifier.Get(apiURL+"/acme/cert/test-cert", false) + require.NoError(t, err) + + assert.NotNil(t, certRes) + assert.Equal(t, "acme.wtf", certRes.Domain) + assert.Equal(t, apiURL+"/acme/cert/test-cert", certRes.CertStableURL) + assert.Equal(t, apiURL+"/acme/cert/test-cert", certRes.CertURL) + assert.Nil(t, certRes.CSR) + assert.Nil(t, certRes.PrivateKey) + assert.Equal(t, certResponseMock, string(certRes.Certificate), "Certificate") + assert.Equal(t, issuerMock, string(certRes.IssuerCertificate), "IssuerCertificate") +} + type resolverMock struct { error error }