2019-03-11 16:56:48 +00:00
|
|
|
package registration
|
2018-12-06 21:50:17 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"errors"
|
|
|
|
"net/http"
|
|
|
|
|
2020-09-02 01:20:01 +00:00
|
|
|
"github.com/go-acme/lego/v4/acme"
|
|
|
|
"github.com/go-acme/lego/v4/acme/api"
|
|
|
|
"github.com/go-acme/lego/v4/log"
|
2018-12-06 21:50:17 +00:00
|
|
|
)
|
|
|
|
|
2023-10-31 13:08:50 +00:00
|
|
|
const mailTo = "mailto:"
|
|
|
|
|
2018-12-06 21:50:17 +00:00
|
|
|
// Resource represents all important information about a registration
|
|
|
|
// of which the client needs to keep track itself.
|
2022-09-06 17:11:36 +00:00
|
|
|
// WARNING: will be removed in the future (acme.ExtendedAccount), https://github.com/go-acme/lego/issues/855.
|
2018-12-06 21:50:17 +00:00
|
|
|
type Resource struct {
|
|
|
|
Body acme.Account `json:"body,omitempty"`
|
|
|
|
URI string `json:"uri,omitempty"`
|
|
|
|
}
|
|
|
|
|
|
|
|
type RegisterOptions struct {
|
|
|
|
TermsOfServiceAgreed bool
|
|
|
|
}
|
|
|
|
|
|
|
|
type RegisterEABOptions struct {
|
|
|
|
TermsOfServiceAgreed bool
|
|
|
|
Kid string
|
|
|
|
HmacEncoded string
|
|
|
|
}
|
|
|
|
|
|
|
|
type Registrar struct {
|
|
|
|
core *api.Core
|
|
|
|
user User
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewRegistrar(core *api.Core, user User) *Registrar {
|
|
|
|
return &Registrar{
|
|
|
|
core: core,
|
|
|
|
user: user,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Register the current account to the ACME server.
|
|
|
|
func (r *Registrar) Register(options RegisterOptions) (*Resource, error) {
|
|
|
|
if r == nil || r.user == nil {
|
|
|
|
return nil, errors.New("acme: cannot register a nil client or user")
|
|
|
|
}
|
|
|
|
|
|
|
|
accMsg := acme.Account{
|
|
|
|
TermsOfServiceAgreed: options.TermsOfServiceAgreed,
|
|
|
|
Contact: []string{},
|
|
|
|
}
|
|
|
|
|
|
|
|
if r.user.GetEmail() != "" {
|
|
|
|
log.Infof("acme: Registering account for %s", r.user.GetEmail())
|
2023-10-31 13:08:50 +00:00
|
|
|
accMsg.Contact = []string{mailTo + r.user.GetEmail()}
|
2018-12-06 21:50:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
account, err := r.core.Accounts.New(accMsg)
|
|
|
|
if err != nil {
|
2021-03-04 19:16:59 +00:00
|
|
|
// seems impossible
|
2020-10-27 11:01:05 +00:00
|
|
|
var errorDetails acme.ProblemDetails
|
|
|
|
if !errors.As(err, &errorDetails) || errorDetails.HTTPStatus != http.StatusConflict {
|
2018-12-06 21:50:17 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return &Resource{URI: account.Location, Body: account.Account}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// RegisterWithExternalAccountBinding Register the current account to the ACME server.
|
|
|
|
func (r *Registrar) RegisterWithExternalAccountBinding(options RegisterEABOptions) (*Resource, error) {
|
|
|
|
accMsg := acme.Account{
|
|
|
|
TermsOfServiceAgreed: options.TermsOfServiceAgreed,
|
|
|
|
Contact: []string{},
|
|
|
|
}
|
|
|
|
|
|
|
|
if r.user.GetEmail() != "" {
|
|
|
|
log.Infof("acme: Registering account for %s", r.user.GetEmail())
|
2023-10-31 13:08:50 +00:00
|
|
|
accMsg.Contact = []string{mailTo + r.user.GetEmail()}
|
2018-12-06 21:50:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
account, err := r.core.Accounts.NewEAB(accMsg, options.Kid, options.HmacEncoded)
|
|
|
|
if err != nil {
|
2021-03-04 19:16:59 +00:00
|
|
|
// seems impossible
|
2020-10-27 11:01:05 +00:00
|
|
|
var errorDetails acme.ProblemDetails
|
|
|
|
if !errors.As(err, &errorDetails) || errorDetails.HTTPStatus != http.StatusConflict {
|
2018-12-06 21:50:17 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return &Resource{URI: account.Location, Body: account.Account}, 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 (r *Registrar) QueryRegistration() (*Resource, error) {
|
2020-10-27 11:01:05 +00:00
|
|
|
if r == nil || r.user == nil || r.user.GetRegistration() == nil {
|
2018-12-06 21:50:17 +00:00
|
|
|
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
|
|
|
|
log.Infof("acme: Querying account for %s", r.user.GetRegistration().URI)
|
|
|
|
|
|
|
|
account, err := r.core.Accounts.Get(r.user.GetRegistration().URI)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return &Resource{
|
|
|
|
Body: account,
|
|
|
|
// Location: header is not returned so this needs to be populated off of existing URI
|
|
|
|
URI: r.user.GetRegistration().URI,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2019-11-19 00:07:46 +00:00
|
|
|
// UpdateRegistration update the user registration on the ACME server.
|
|
|
|
func (r *Registrar) UpdateRegistration(options RegisterOptions) (*Resource, error) {
|
|
|
|
if r == nil || r.user == nil {
|
|
|
|
return nil, errors.New("acme: cannot update a nil client or user")
|
|
|
|
}
|
|
|
|
|
|
|
|
accMsg := acme.Account{
|
|
|
|
TermsOfServiceAgreed: options.TermsOfServiceAgreed,
|
|
|
|
Contact: []string{},
|
|
|
|
}
|
|
|
|
|
|
|
|
if r.user.GetEmail() != "" {
|
|
|
|
log.Infof("acme: Registering account for %s", r.user.GetEmail())
|
2023-10-31 13:08:50 +00:00
|
|
|
accMsg.Contact = []string{mailTo + r.user.GetEmail()}
|
2019-11-19 00:07:46 +00:00
|
|
|
}
|
|
|
|
|
2020-05-26 18:04:54 +00:00
|
|
|
accountURL := r.user.GetRegistration().URI
|
|
|
|
|
|
|
|
account, err := r.core.Accounts.Update(accountURL, accMsg)
|
2019-11-19 00:07:46 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-05-26 18:04:54 +00:00
|
|
|
return &Resource{URI: accountURL, Body: account}, nil
|
2019-11-19 00:07:46 +00:00
|
|
|
}
|
|
|
|
|
2018-12-06 21:50:17 +00:00
|
|
|
// DeleteRegistration deletes the client's user registration from the ACME server.
|
|
|
|
func (r *Registrar) DeleteRegistration() error {
|
|
|
|
if r == nil || r.user == nil {
|
|
|
|
return errors.New("acme: cannot unregister a nil client or user")
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Infof("acme: Deleting account for %s", r.user.GetEmail())
|
|
|
|
|
|
|
|
return r.core.Accounts.Deactivate(r.user.GetRegistration().URI)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ResolveAccountByKey will attempt to look up an account using the given account key
|
|
|
|
// and return its registration resource.
|
|
|
|
func (r *Registrar) ResolveAccountByKey() (*Resource, error) {
|
|
|
|
log.Infof("acme: Trying to resolve account by key")
|
|
|
|
|
|
|
|
accMsg := acme.Account{OnlyReturnExisting: true}
|
2020-05-26 17:06:38 +00:00
|
|
|
account, err := r.core.Accounts.New(accMsg)
|
2018-12-06 21:50:17 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2020-05-26 17:06:38 +00:00
|
|
|
return &Resource{URI: account.Location, Body: account.Account}, nil
|
2018-12-06 21:50:17 +00:00
|
|
|
}
|