diff --git a/acme/internal/acme/acme.go b/acme/internal/acme/acme.go index a16f0bb..a41b6ba 100644 --- a/acme/internal/acme/acme.go +++ b/acme/internal/acme/acme.go @@ -185,13 +185,35 @@ func (c *Client) FetchCert(ctx context.Context, url string, bundle bool) ([][]by } } +// AcceptTOS always returns true to indicate the acceptance of a CA Terms of Service +// during account registration. See Register method of Client for more details. +func AcceptTOS(string) bool { return true } + // Register creates a new account registration by following the "new-reg" flow. // It returns registered account. The a argument is not modified. -func (c *Client) Register(a *Account) (*Account, error) { +// +// The registration may require the caller to agree to the CA Terms of Service (TOS). +// If so, and the account has not indicated the acceptance of the terms (see Account for details), +// Register calls prompt with a TOS URL provided by the CA. Prompt should report +// whether the caller agrees to the terms. To always accept the terms, the caller can use AcceptTOS. +func (c *Client) Register(a *Account, prompt func(tos string) bool) (*Account, error) { if _, err := c.Discover(); err != nil { return nil, err } - return c.doReg(c.dir.RegURL, "new-reg", a) + + var err error + if a, err = c.doReg(c.dir.RegURL, "new-reg", a); err != nil { + return nil, err + } + var accept bool + if a.CurrentTerms != "" && a.CurrentTerms != a.AgreedTerms { + accept = prompt(a.CurrentTerms) + } + if accept { + a.AgreedTerms = a.CurrentTerms + a, err = c.UpdateReg(a) + } + return a, err } // GetReg retrieves an existing registration. diff --git a/acme/internal/acme/acme_test.go b/acme/internal/acme/acme_test.go index 6d7c424..eae8f66 100644 --- a/acme/internal/acme/acme_test.go +++ b/acme/internal/acme/acme_test.go @@ -117,10 +117,18 @@ func TestRegister(t *testing.T) { })) defer ts.Close() + prompt := func(url string) bool { + const terms = "https://ca.tld/acme/terms" + if url != terms { + t.Errorf("prompt url = %q; want %q", url, terms) + } + return false + } + c := Client{Key: testKey, dir: &Directory{RegURL: ts.URL}} a := &Account{Contact: contacts} var err error - if a, err = c.Register(a); err != nil { + if a, err = c.Register(a, prompt); err != nil { t.Fatal(err) } if a.URI != "https://ca.tld/acme/reg/1" { diff --git a/acme/internal/acme/types.go b/acme/internal/acme/types.go index e64dc11..702be79 100644 --- a/acme/internal/acme/types.go +++ b/acme/internal/acme/types.go @@ -25,7 +25,8 @@ type Account struct { Contact []string // The terms user has agreed to. - // Zero value indicates that the user hasn't agreed yet. + // A value not matching CurrentTerms indicates that the user hasn't agreed + // to the actual Terms of Service of the CA. AgreedTerms string // Actual terms of a CA.