145 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			145 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Go
		
	
	
	
| package acme
 | |
| 
 | |
| import (
 | |
| 	"crypto"
 | |
| 	"encoding/json"
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"net/http"
 | |
| 	"reflect"
 | |
| )
 | |
| 
 | |
| // NewAccount registers a new account with the acme service
 | |
| // Note this function is essentially deprecated and only present for backwards compatibility.
 | |
| // New programs should implement NewAccountOptions instead.
 | |
| func (c Client) NewAccount(privateKey crypto.Signer, onlyReturnExisting, termsOfServiceAgreed bool, contact ...string) (Account, error) {
 | |
| 	var opts []NewAccountOptionFunc
 | |
| 	if onlyReturnExisting {
 | |
| 		opts = append(opts, NewAcctOptOnlyReturnExisting())
 | |
| 	}
 | |
| 	if termsOfServiceAgreed {
 | |
| 		opts = append(opts, NewAcctOptAgreeTOS())
 | |
| 	}
 | |
| 	if contact != nil && len(contact) > 0 {
 | |
| 		opts = append(opts, NewAcctOptWithContacts(contact...))
 | |
| 	}
 | |
| 
 | |
| 	return c.NewAccountOptions(privateKey, opts...)
 | |
| }
 | |
| 
 | |
| // NewAccountOptions registers an account with an acme server with the provided options.
 | |
| func (c Client) NewAccountOptions(privateKey crypto.Signer, options ...NewAccountOptionFunc) (Account, error) {
 | |
| 	newAccountReq := NewAccountRequest{}
 | |
| 	account := Account{}
 | |
| 
 | |
| 	for _, opt := range options {
 | |
| 		if err := opt(privateKey, &account, &newAccountReq, c); err != nil {
 | |
| 			return account, err
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	resp, err := c.post(c.dir.NewAccount, "", privateKey, newAccountReq, &account, http.StatusOK, http.StatusCreated)
 | |
| 	if err != nil {
 | |
| 		return account, err
 | |
| 	}
 | |
| 
 | |
| 	account.URL = resp.Header.Get("Location")
 | |
| 	account.PrivateKey = privateKey
 | |
| 
 | |
| 	if account.Thumbprint == "" {
 | |
| 		account.Thumbprint, err = JWKThumbprint(account.PrivateKey.Public())
 | |
| 		if err != nil {
 | |
| 			return account, fmt.Errorf("acme: error computing account thumbprint: %v", err)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return account, nil
 | |
| }
 | |
| 
 | |
| // UpdateAccount updates an existing account with the acme service.
 | |
| func (c Client) UpdateAccount(account Account, contact ...string) (Account, error) {
 | |
| 	var updateAccountReq interface{}
 | |
| 
 | |
| 	if !reflect.DeepEqual(account.Contact, contact) {
 | |
| 		// Only provide a non-nil updateAccountReq when there is an update to be made.
 | |
| 		updateAccountReq = struct {
 | |
| 			Contact []string `json:"contact,omitempty"`
 | |
| 		}{
 | |
| 			Contact: contact,
 | |
| 		}
 | |
| 	} else {
 | |
| 		// Otherwise use "" to trigger a POST-as-GET to fetch up-to-date account
 | |
| 		// information from the acme service.
 | |
| 		updateAccountReq = ""
 | |
| 	}
 | |
| 
 | |
| 	_, err := c.post(account.URL, account.URL, account.PrivateKey, updateAccountReq, &account, http.StatusOK)
 | |
| 	if err != nil {
 | |
| 		return account, err
 | |
| 	}
 | |
| 
 | |
| 	if account.Thumbprint == "" {
 | |
| 		account.Thumbprint, err = JWKThumbprint(account.PrivateKey.Public())
 | |
| 		if err != nil {
 | |
| 			return account, fmt.Errorf("acme: error computing account thumbprint: %v", err)
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return account, nil
 | |
| }
 | |
| 
 | |
| // AccountKeyChange rolls over an account to a new key.
 | |
| func (c Client) AccountKeyChange(account Account, newPrivateKey crypto.Signer) (Account, error) {
 | |
| 	oldJwkKeyPub, err := jwkEncode(account.PrivateKey.Public())
 | |
| 	if err != nil {
 | |
| 		return account, fmt.Errorf("acme: error encoding new private key: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	keyChangeReq := struct {
 | |
| 		Account string          `json:"account"`
 | |
| 		OldKey  json.RawMessage `json:"oldKey"`
 | |
| 	}{
 | |
| 		Account: account.URL,
 | |
| 		OldKey:  []byte(oldJwkKeyPub),
 | |
| 	}
 | |
| 
 | |
| 	innerJws, err := jwsEncodeJSON(keyChangeReq, newPrivateKey, "", "", c.dir.KeyChange)
 | |
| 	if err != nil {
 | |
| 		return account, fmt.Errorf("acme: error encoding inner jws: %v", err)
 | |
| 	}
 | |
| 
 | |
| 	if _, err := c.post(c.dir.KeyChange, account.URL, account.PrivateKey, json.RawMessage(innerJws), nil, http.StatusOK); err != nil {
 | |
| 		return account, err
 | |
| 	}
 | |
| 
 | |
| 	account.PrivateKey = newPrivateKey
 | |
| 
 | |
| 	return account, nil
 | |
| }
 | |
| 
 | |
| // DeactivateAccount deactivates a given account.
 | |
| func (c Client) DeactivateAccount(account Account) (Account, error) {
 | |
| 	deactivateReq := struct {
 | |
| 		Status string `json:"status"`
 | |
| 	}{
 | |
| 		Status: "deactivated",
 | |
| 	}
 | |
| 
 | |
| 	_, err := c.post(account.URL, account.URL, account.PrivateKey, deactivateReq, &account, http.StatusOK)
 | |
| 
 | |
| 	return account, err
 | |
| }
 | |
| 
 | |
| // FetchOrderList fetches a list of orders from the account url provided in the account Orders field
 | |
| func (c Client) FetchOrderList(account Account) (OrderList, error) {
 | |
| 	orderList := OrderList{}
 | |
| 
 | |
| 	if account.Orders == "" {
 | |
| 		return orderList, errors.New("no order list for account")
 | |
| 	}
 | |
| 
 | |
| 	_, err := c.post(account.Orders, account.URL, account.PrivateKey, "", &orderList, http.StatusOK)
 | |
| 
 | |
| 	return orderList, err
 | |
| }
 |