From 3028225371bb24abaac5b34843ce96433ef2ee68 Mon Sep 17 00:00:00 2001
From: Chris Marchesi <inbox@vancluevertech.com>
Date: Mon, 6 Jun 2016 11:45:22 -0700
Subject: [PATCH] reg: Add Query and Delete functions

Add 2 new functions to acme.Client for registration stuff:

 * QueryRegistration: This performs a POST on the client
   registration's URI and gets the updated registration info.
 * DeleteRegistration: This deletes the registration as currently
   configured in the client.

The latter, while a part of the IETF draft, may not be 100%
functional in LE yet, my tests showed that resources were still
available after deletion.
---
 acme/client.go   | 62 ++++++++++++++++++++++++++++++++++++++++++++++++
 acme/messages.go |  1 +
 2 files changed, 63 insertions(+)

diff --git a/acme/client.go b/acme/client.go
index 5bda6bc2..445dc2bd 100644
--- a/acme/client.go
+++ b/acme/client.go
@@ -189,6 +189,68 @@ func (c *Client) Register() (*RegistrationResource, error) {
 	return reg, nil
 }
 
+// DeleteRegistration deletes the client's user registration from the ACME
+// server.
+func (c *Client) DeleteRegistration() error {
+	if c == nil || c.user == nil {
+		return errors.New("acme: cannot unregister a nil client or user")
+	}
+	logf("[INFO] acme: Deleting account for %s", c.user.GetEmail())
+
+	regMsg := registrationMessage{
+		Resource: "reg",
+		Delete:   true,
+	}
+
+	_, err := postJSON(c.jws, c.user.GetRegistration().URI, regMsg, nil)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+// QueryRegistration runs a POST request on the client's registration and
+// returns the result.
+//
+// This is similar to the Register function, but acting on an existing
+// registration link and resource.
+func (c *Client) QueryRegistration() (*RegistrationResource, error) {
+	if c == nil || c.user == nil {
+		return nil, errors.New("acme: cannot query the registration of a nil client or user")
+	}
+	// Log the URL here instead of the email as the email may not be set
+	logf("[INFO] acme: Querying account for %s", c.user.GetRegistration().URI)
+
+	regMsg := registrationMessage{
+		Resource: "reg",
+	}
+
+	var serverReg Registration
+	hdr, err := postJSON(c.jws, c.user.GetRegistration().URI, regMsg, &serverReg)
+	if err != nil {
+		return nil, err
+	}
+
+	reg := &RegistrationResource{Body: serverReg}
+
+	links := parseLinks(hdr["Link"])
+	// Location: header is not returned so this needs to be populated off of
+	// existing URI
+	reg.URI = c.user.GetRegistration().URI
+	if links["terms-of-service"] != "" {
+		reg.TosURL = links["terms-of-service"]
+	}
+
+	if links["next"] != "" {
+		reg.NewAuthzURL = links["next"]
+	} else {
+		return nil, errors.New("acme: No new-authz link in response to registration query")
+	}
+
+	return reg, nil
+}
+
 // AgreeToTOS updates the Client registration and sends the agreement to
 // the server.
 func (c *Client) AgreeToTOS() error {
diff --git a/acme/messages.go b/acme/messages.go
index d1fac920..a6539b96 100644
--- a/acme/messages.go
+++ b/acme/messages.go
@@ -22,6 +22,7 @@ type recoveryKeyMessage struct {
 type registrationMessage struct {
 	Resource string   `json:"resource"`
 	Contact  []string `json:"contact"`
+	Delete   bool     `json:"delete,omitempty"`
 	//	RecoveryKey recoveryKeyMessage `json:"recoveryKey,omitempty"`
 }