From bbc6a174d9ee7aa6d7b088de8f2169ca55e16841 Mon Sep 17 00:00:00 2001 From: Fernandez Ludovic Date: Thu, 26 Feb 2026 17:05:39 +0100 Subject: [PATCH] feat: replace registration.Resource --- acme/commons.go | 2 +- cmd/cmd_list_accounts.go | 4 +- cmd/cmd_register.go | 3 +- cmd/cmd_renew.go | 2 +- cmd/cmd_run.go | 6 +-- cmd/internal/migrate/accounts.go | 30 +++++++++--- cmd/internal/storage/account.go | 12 ++--- cmd/internal/storage/accounts.go | 6 +-- cmd/internal/storage/accounts_test.go | 13 +++-- cmd/internal/storage/testdata/account.json | 20 ++++---- .../test@example.com/RSA4096/account.json | 6 +-- cmd/setup_challenges.go | 13 ++--- e2e/challenges_test.go | 21 +++++---- e2e/dnschallenge/dns_challenges_test.go | 9 ++-- .../dns_persist_challenges_test.go | 24 +++++----- lego/client.go | 2 +- lego/client_test.go | 12 ++--- registration/registar.go | 47 +++++++++---------- registration/registar_test.go | 4 +- registration/user.go | 4 +- registration/user_test.go | 10 ++-- 21 files changed, 130 insertions(+), 120 deletions(-) diff --git a/acme/commons.go b/acme/commons.go index b665ca6d6..a874a6d3d 100644 --- a/acme/commons.go +++ b/acme/commons.go @@ -86,7 +86,7 @@ type ExtendedAccount struct { Account // Contains the value of the response header `Location` - Location string `json:"-"` + Location string `json:"accountURL,omitempty"` } // Account the ACME account Object. diff --git a/cmd/cmd_list_accounts.go b/cmd/cmd_list_accounts.go index a117878b9..fd7cc154b 100644 --- a/cmd/cmd_list_accounts.go +++ b/cmd/cmd_list_accounts.go @@ -100,9 +100,9 @@ func readAccounts(cmd *cli.Command) ([]ListAccount, error) { var server string - uri, err := url.Parse(account.Registration.URI) + uri, err := url.Parse(account.Registration.Location) if err != nil { - log.Error("Parsing account registration URI.", log.ErrorAttr(err)) + log.Error("Parsing account registration Location.", log.ErrorAttr(err)) } else { server = fmt.Sprintf("%s://%s", uri.Scheme, uri.Host) } diff --git a/cmd/cmd_register.go b/cmd/cmd_register.go index d17b18b80..30815846f 100644 --- a/cmd/cmd_register.go +++ b/cmd/cmd_register.go @@ -8,6 +8,7 @@ import ( "os" "strings" + "github.com/go-acme/lego/v5/acme" "github.com/go-acme/lego/v5/certcrypto" "github.com/go-acme/lego/v5/cmd/internal/storage" "github.com/go-acme/lego/v5/lego" @@ -77,7 +78,7 @@ func register(ctx context.Context, cmd *cli.Command) error { return nil } -func registerAccount(ctx context.Context, cmd *cli.Command, client *lego.Client) (*registration.Resource, error) { +func registerAccount(ctx context.Context, cmd *cli.Command, client *lego.Client) (*acme.ExtendedAccount, error) { accepted := handleTOS(cmd, client) if !accepted { log.Fatal("You did not accept the TOS. Unable to proceed.") diff --git a/cmd/cmd_renew.go b/cmd/cmd_renew.go index c258abe7e..e7ab2d4e5 100644 --- a/cmd/cmd_renew.go +++ b/cmd/cmd_renew.go @@ -90,7 +90,7 @@ func renew(ctx context.Context, cmd *cli.Command) error { return nil, fmt.Errorf("new client: %w", err) } - setupChallenges(cmd, client, account) + setupChallenges(cmd, client, account.GetRegistration()) return client, nil }) diff --git a/cmd/cmd_run.go b/cmd/cmd_run.go index fa3c1d024..0660345f5 100644 --- a/cmd/cmd_run.go +++ b/cmd/cmd_run.go @@ -4,13 +4,13 @@ import ( "context" "fmt" + "github.com/go-acme/lego/v5/acme" "github.com/go-acme/lego/v5/certcrypto" "github.com/go-acme/lego/v5/certificate" "github.com/go-acme/lego/v5/cmd/internal/hook" "github.com/go-acme/lego/v5/cmd/internal/storage" "github.com/go-acme/lego/v5/lego" "github.com/go-acme/lego/v5/log" - "github.com/go-acme/lego/v5/registration" "github.com/urfave/cli/v3" ) @@ -60,7 +60,7 @@ func run(ctx context.Context, cmd *cli.Command) error { } if account.Registration == nil { - var reg *registration.Resource + var reg *acme.ExtendedAccount reg, err = registerAccount(ctx, cmd, client) if err != nil { @@ -75,7 +75,7 @@ func run(ctx context.Context, cmd *cli.Command) error { fmt.Printf(rootPathWarningMessage, accountsStorage.GetRootPath()) } - setupChallenges(cmd, client, account) + setupChallenges(cmd, client, account.GetRegistration()) certRes, err := obtainCertificate(ctx, cmd, client) if err != nil { diff --git a/cmd/internal/migrate/accounts.go b/cmd/internal/migrate/accounts.go index 7f8f7baa6..b13aabcda 100644 --- a/cmd/internal/migrate/accounts.go +++ b/cmd/internal/migrate/accounts.go @@ -10,12 +10,23 @@ import ( "os" "path/filepath" + "github.com/go-acme/lego/v5/acme" "github.com/go-acme/lego/v5/certcrypto" "github.com/go-acme/lego/v5/cmd/internal/storage" "github.com/go-acme/lego/v5/log" "github.com/mattn/go-zglob" ) +type OldAccount struct { + Email string `json:"email"` + Registration *OldResource `json:"registration"` +} + +type OldResource struct { + Body acme.Account `json:"body"` + URI string `json:"uri,omitempty"` +} + // Accounts migrates the old accounts directory structure to the new one. func Accounts(root string) error { matches, err := zglob.Glob(filepath.Join(root, "**", "account.json")) @@ -31,25 +42,32 @@ func Accounts(root string) error { return fmt.Errorf("could not read the account file %q: %w", srcAccountFilePath, err) } - var account storage.Account + var oldAccount OldAccount - err = json.Unmarshal(data, &account) + err = json.Unmarshal(data, &oldAccount) if err != nil { return fmt.Errorf("could not parse the account file %q: %w", srcAccountFilePath, err) } - account.ID = account.GetID() + account := storage.Account{ + ID: oldAccount.Email, + Email: oldAccount.Email, + Registration: &acme.ExtendedAccount{ + Account: oldAccount.Registration.Body, + Location: oldAccount.Registration.URI, + }, + } accountsDir := filepath.Dir(srcAccountFilePath) - srcKeyPath := filepath.Join(accountsDir, "keys", account.ID+storage.ExtKey) + srcKeyPath := filepath.Join(accountsDir, "keys", account.GetID()+storage.ExtKey) account.KeyType, err = getKeyType(srcKeyPath) if err != nil { return fmt.Errorf("could not guess the account key type: %w", err) } - newAccountDir := filepath.Join(accountsDir, string(account.KeyType)) + newAccountDir := filepath.Join(accountsDir, string(account.GetKeyType())) err = os.MkdirAll(newAccountDir, 0o700) if err != nil { @@ -58,7 +76,7 @@ func Accounts(root string) error { // Rename the private key file. - dstKeyPath := filepath.Join(newAccountDir, account.ID+storage.ExtKey) + dstKeyPath := filepath.Join(newAccountDir, account.GetID()+storage.ExtKey) err = os.Rename(srcKeyPath, dstKeyPath) if err != nil { diff --git a/cmd/internal/storage/account.go b/cmd/internal/storage/account.go index 6fc13524e..892552137 100644 --- a/cmd/internal/storage/account.go +++ b/cmd/internal/storage/account.go @@ -3,18 +3,18 @@ package storage import ( "crypto" + "github.com/go-acme/lego/v5/acme" "github.com/go-acme/lego/v5/certcrypto" - "github.com/go-acme/lego/v5/registration" ) const AccountIDPlaceholder = "noemail@example.com" // Account represents a users local saved credentials. type Account struct { - ID string `json:"id"` - Email string `json:"email"` - KeyType certcrypto.KeyType `json:"keyType"` - Registration *registration.Resource `json:"registration"` + ID string `json:"id"` + Email string `json:"email"` + KeyType certcrypto.KeyType `json:"keyType"` + Registration *acme.ExtendedAccount `json:"registration"` key crypto.PrivateKey } @@ -46,7 +46,7 @@ func (a *Account) GetPrivateKey() crypto.PrivateKey { } // GetRegistration returns the server registration. -func (a *Account) GetRegistration() *registration.Resource { +func (a *Account) GetRegistration() *acme.ExtendedAccount { return a.Registration } diff --git a/cmd/internal/storage/accounts.go b/cmd/internal/storage/accounts.go index a10dbb0e4..b1fed22d2 100644 --- a/cmd/internal/storage/accounts.go +++ b/cmd/internal/storage/accounts.go @@ -13,10 +13,10 @@ import ( "path/filepath" "strings" + "github.com/go-acme/lego/v5/acme" "github.com/go-acme/lego/v5/certcrypto" "github.com/go-acme/lego/v5/lego" "github.com/go-acme/lego/v5/log" - "github.com/go-acme/lego/v5/registration" ) const ( @@ -166,7 +166,7 @@ func (s *AccountsStorage) getAccount(ctx context.Context, keyType certcrypto.Key account.key, err = s.readPrivateKey(keyType, effectiveAccountID) if err == nil { - if account.Registration != nil && account.Registration.Body.Status != "" { + if account.Registration != nil && account.Registration.Status != "" { return account, nil } @@ -293,7 +293,7 @@ func (s *AccountsStorage) getRootUserPath(effectiveAccountID string) string { } // tryRecoverRegistration tries to recover the registration from the private key. -func (s *AccountsStorage) tryRecoverRegistration(ctx context.Context, privateKey crypto.PrivateKey) (*registration.Resource, error) { +func (s *AccountsStorage) tryRecoverRegistration(ctx context.Context, privateKey crypto.PrivateKey) (*acme.ExtendedAccount, error) { // couldn't load account but got a key. Try to look the account up. config := lego.NewConfig(&Account{key: privateKey}) config.CADirURL = s.server.String() diff --git a/cmd/internal/storage/accounts_test.go b/cmd/internal/storage/accounts_test.go index 9dc607805..e78fe30cf 100644 --- a/cmd/internal/storage/accounts_test.go +++ b/cmd/internal/storage/accounts_test.go @@ -9,7 +9,6 @@ import ( "github.com/go-acme/lego/v5/acme" "github.com/go-acme/lego/v5/certcrypto" - "github.com/go-acme/lego/v5/registration" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -46,8 +45,8 @@ func TestAccountsStorage_Save(t *testing.T) { Email: "account@example.com", ID: accountID, KeyType: keyType, - Registration: ®istration.Resource{ - Body: acme.Account{ + Registration: &acme.ExtendedAccount{ + Account: acme.Account{ Status: "valid", Contact: []string{"contact@example.com"}, TermsOfServiceAgreed: true, @@ -55,7 +54,7 @@ func TestAccountsStorage_Save(t *testing.T) { OnlyReturnExisting: true, ExternalAccountBinding: []byte(`"EAB"`), }, - URI: "https://ame.example.com", + Location: "https://ame.example.com", }, key: crypto.PrivateKey(""), } @@ -116,11 +115,11 @@ func TestAccountsStorage_Get_existingAccount(t *testing.T) { assert.Equal(t, "test@example.com", account.GetID()) assert.Equal(t, certcrypto.RSA4096, account.KeyType) - expectedRegistration := ®istration.Resource{ - Body: acme.Account{ + expectedRegistration := &acme.ExtendedAccount{ + Account: acme.Account{ Status: "valid", }, - URI: "https://example.org/acme/acct/123456", + Location: "https://example.org/acme/acct/123456", } assert.Equal(t, expectedRegistration, account.GetRegistration()) diff --git a/cmd/internal/storage/testdata/account.json b/cmd/internal/storage/testdata/account.json index 21c0677ee..b23eac038 100644 --- a/cmd/internal/storage/testdata/account.json +++ b/cmd/internal/storage/testdata/account.json @@ -3,16 +3,14 @@ "email": "account@example.com", "keyType": "RSA4096", "registration": { - "body": { - "status": "valid", - "contact": [ - "contact@example.com" - ], - "termsOfServiceAgreed": true, - "orders": "https://ame.example.com/orders/123456", - "onlyReturnExisting": true, - "externalAccountBinding": "EAB" - }, - "uri": "https://ame.example.com" + "status": "valid", + "contact": [ + "contact@example.com" + ], + "termsOfServiceAgreed": true, + "orders": "https://ame.example.com/orders/123456", + "onlyReturnExisting": true, + "externalAccountBinding": "EAB", + "accountURL": "https://ame.example.com" } } diff --git a/cmd/internal/storage/testdata/accounts/test@example.com/RSA4096/account.json b/cmd/internal/storage/testdata/accounts/test@example.com/RSA4096/account.json index 34f8101bb..c099b63e7 100644 --- a/cmd/internal/storage/testdata/accounts/test@example.com/RSA4096/account.json +++ b/cmd/internal/storage/testdata/accounts/test@example.com/RSA4096/account.json @@ -3,9 +3,7 @@ "email": "account@example.com", "keyType": "RSA4096", "registration": { - "body": { - "status": "valid" - }, - "uri": "https://example.org/acme/acct/123456" + "status": "valid", + "accountURL": "https://example.org/acme/acct/123456" } } diff --git a/cmd/setup_challenges.go b/cmd/setup_challenges.go index 1d34e13d3..3b53ba68b 100644 --- a/cmd/setup_challenges.go +++ b/cmd/setup_challenges.go @@ -1,13 +1,13 @@ package cmd import ( - "errors" "fmt" "log/slog" "net" "strings" "time" + "github.com/go-acme/lego/v5/acme" "github.com/go-acme/lego/v5/challenge" "github.com/go-acme/lego/v5/challenge/dns01" "github.com/go-acme/lego/v5/challenge/dnspersist01" @@ -19,12 +19,11 @@ import ( "github.com/go-acme/lego/v5/providers/http/memcached" "github.com/go-acme/lego/v5/providers/http/s3" "github.com/go-acme/lego/v5/providers/http/webroot" - "github.com/go-acme/lego/v5/registration" "github.com/urfave/cli/v3" ) //nolint:gocyclo // challenge setup dispatch is expected to branch by enabled challenge type. -func setupChallenges(cmd *cli.Command, client *lego.Client, account registration.User) { +func setupChallenges(cmd *cli.Command, client *lego.Client, account *acme.ExtendedAccount) { if !cmd.Bool(flgHTTP) && !cmd.Bool(flgTLS) && !cmd.IsSet(flgDNS) && !cmd.Bool(flgDNSPersist) { log.Fatal(fmt.Sprintf("No challenge selected. You must specify at least one challenge: `--%s`, `--%s`, `--%s`, `--%s`.", flgHTTP, flgTLS, flgDNS, flgDNSPersist)) @@ -213,11 +212,7 @@ func setupDNS(cmd *cli.Command, client *lego.Client) error { return err } -func setupDNSPersist(cmd *cli.Command, client *lego.Client, account registration.User) error { - if account == nil || account.GetRegistration() == nil || account.GetRegistration().URI == "" { - return errors.New("dns-persist-01 requires a registered account with an account URI") - } - +func setupDNSPersist(cmd *cli.Command, client *lego.Client, account *acme.ExtendedAccount) error { err := validatePropagationExclusiveOptions(cmd, flgDNSPersistPropagationWait, flgDNSPersistPropagationDisableANS, flgDNSPersistIssuerDomainName) if err != nil { return err @@ -236,7 +231,7 @@ func setupDNSPersist(cmd *cli.Command, client *lego.Client, account registration shouldWait := cmd.IsSet(flgDNSPersistPropagationWait) return client.Challenge.SetDNSPersist01( - dnspersist01.WithAccountURI(account.GetRegistration().URI), + dnspersist01.WithAccountURI(account.Location), dnspersist01.WithIssuerDomainName(cmd.String(flgDNSPersistIssuerDomainName)), dnspersist01.CondOptions(cmd.IsSet(flgDNSPersistPersistUntil), dnspersist01.WithPersistUntil(cmd.Timestamp(flgDNSPersistPersistUntil)), diff --git a/e2e/challenges_test.go b/e2e/challenges_test.go index c0353afd7..00485128e 100644 --- a/e2e/challenges_test.go +++ b/e2e/challenges_test.go @@ -13,6 +13,7 @@ import ( "testing" "time" + "github.com/go-acme/lego/v5/acme" "github.com/go-acme/lego/v5/certcrypto" "github.com/go-acme/lego/v5/certificate" "github.com/go-acme/lego/v5/challenge/http01" @@ -420,9 +421,9 @@ func TestChallengeHTTP_Client_Registration_QueryRegistration(t *testing.T) { require.NotNil(t, resource) - assert.Equal(t, "valid", resource.Body.Status) - assert.Regexp(t, `https://localhost:14000/list-orderz/[\w\d]+`, resource.Body.Orders) - assert.Regexp(t, `https://localhost:14000/my-account/[\w\d]+`, resource.URI) + assert.Equal(t, "valid", resource.Status) + assert.Regexp(t, `https://localhost:14000/list-orderz/[\w\d]+`, resource.Orders) + assert.Regexp(t, `https://localhost:14000/my-account/[\w\d]+`, resource.Location) } func TestChallengeTLS_Client_Obtain(t *testing.T) { @@ -588,25 +589,25 @@ func TestRegistrar_UpdateAccount(t *testing.T) { regOptions := registration.RegisterOptions{TermsOfServiceAgreed: true} reg, err := client.Registration.Register(ctx, regOptions) require.NoError(t, err) - require.Equal(t, []string{"mailto:" + testEmail1}, reg.Body.Contact) + require.Equal(t, []string{"mailto:" + testEmail1}, reg.Contact) user.registration = reg user.email = testEmail2 resource, err := client.Registration.UpdateRegistration(ctx, regOptions) require.NoError(t, err) - require.Equal(t, []string{"mailto:" + testEmail2}, resource.Body.Contact) - require.Equal(t, reg.URI, resource.URI) + require.Equal(t, []string{"mailto:" + testEmail2}, resource.Contact) + require.Equal(t, reg.Location, resource.Location) } type fakeUser struct { email string privateKey crypto.PrivateKey - registration *registration.Resource + registration *acme.ExtendedAccount } -func (f *fakeUser) GetEmail() string { return f.email } -func (f *fakeUser) GetRegistration() *registration.Resource { return f.registration } -func (f *fakeUser) GetPrivateKey() crypto.PrivateKey { return f.privateKey } +func (f *fakeUser) GetEmail() string { return f.email } +func (f *fakeUser) GetRegistration() *acme.ExtendedAccount { return f.registration } +func (f *fakeUser) GetPrivateKey() crypto.PrivateKey { return f.privateKey } func createTestCSRFile(t *testing.T, raw bool) string { t.Helper() diff --git a/e2e/dnschallenge/dns_challenges_test.go b/e2e/dnschallenge/dns_challenges_test.go index 8b1faa9a5..81695ff2e 100644 --- a/e2e/dnschallenge/dns_challenges_test.go +++ b/e2e/dnschallenge/dns_challenges_test.go @@ -9,6 +9,7 @@ import ( "os" "testing" + "github.com/go-acme/lego/v5/acme" "github.com/go-acme/lego/v5/certificate" "github.com/go-acme/lego/v5/challenge/dns01" "github.com/go-acme/lego/v5/e2e/loader" @@ -193,12 +194,12 @@ func TestChallengeDNS_Client_Obtain_profile(t *testing.T) { type fakeUser struct { email string privateKey crypto.PrivateKey - registration *registration.Resource + registration *acme.ExtendedAccount } -func (f *fakeUser) GetEmail() string { return f.email } -func (f *fakeUser) GetRegistration() *registration.Resource { return f.registration } -func (f *fakeUser) GetPrivateKey() crypto.PrivateKey { return f.privateKey } +func (f *fakeUser) GetEmail() string { return f.email } +func (f *fakeUser) GetRegistration() *acme.ExtendedAccount { return f.registration } +func (f *fakeUser) GetPrivateKey() crypto.PrivateKey { return f.privateKey } func mockDefault(t *testing.T) { t.Helper() diff --git a/e2e/dnschallenge/dns_persist_challenges_test.go b/e2e/dnschallenge/dns_persist_challenges_test.go index 7d9a56b3c..4577772b2 100644 --- a/e2e/dnschallenge/dns_persist_challenges_test.go +++ b/e2e/dnschallenge/dns_persist_challenges_test.go @@ -55,16 +55,16 @@ func TestChallengeDNSPersist_Client_Obtain(t *testing.T) { reg, err := client.Registration.Register(context.Background(), registration.RegisterOptions{TermsOfServiceAgreed: true}) require.NoError(t, err) - require.NotEmpty(t, reg.URI) + require.NotEmpty(t, reg.Location) user.registration = reg - updateDNS(t, reg.URI, testPersistBaseDomain) + updateDNS(t, reg.Location, testPersistBaseDomain) mockDefaultPersist(t) err = client.Challenge.SetDNSPersist01( - dnspersist01.WithAccountURI(reg.URI), + dnspersist01.WithAccountURI(reg.Location), dnspersist01.DisableAuthoritativeNssPropagationRequirement(), ) require.NoError(t, err) @@ -246,7 +246,7 @@ func createCLIAccountState(t *testing.T, email string) string { reg, err := client.Registration.Register(context.Background(), registration.RegisterOptions{TermsOfServiceAgreed: true}) require.NoError(t, err) - require.NotEmpty(t, reg.URI) + require.NotEmpty(t, reg.Location) keyType := certcrypto.EC256 @@ -261,10 +261,10 @@ func createCLIAccountState(t *testing.T, email string) string { accountPath := filepath.Join(accountPathRoot, "account.json") content, err := json.MarshalIndent(struct { - ID string `json:"id"` - Email string `json:"email"` - KeyType certcrypto.KeyType `json:"keyType"` - Registration *registration.Resource `json:"registration"` + ID string `json:"id"` + Email string `json:"email"` + KeyType certcrypto.KeyType `json:"keyType"` + Registration *acme.ExtendedAccount `json:"registration"` }{ ID: email, Email: email, @@ -276,14 +276,14 @@ func createCLIAccountState(t *testing.T, email string) string { err = os.WriteFile(accountPath, content, 0o600) require.NoError(t, err) - return reg.URI + return reg.Location } func waitForAccountFile(ctx context.Context, email string) (string, error) { accountPath := filepath.Join(getAccountPath(email, certcrypto.EC256), "account.json") type accountFile struct { - Registration *registration.Resource `json:"registration"` + Registration *acme.ExtendedAccount `json:"registration"` } return backoff.Retry(ctx, @@ -304,8 +304,8 @@ func waitForAccountFile(ctx context.Context, email string) (string, error) { return "", err } - if account.Registration != nil && account.Registration.URI != "" { - return account.Registration.URI, nil + if account.Registration != nil && account.Registration.Location != "" { + return account.Registration.Location, nil } return "", errors.New("account URI not found") diff --git a/lego/client.go b/lego/client.go index 25d263b1d..d46489e72 100644 --- a/lego/client.go +++ b/lego/client.go @@ -42,7 +42,7 @@ func NewClient(config *Config) (*Client, error) { var kid string if reg := config.User.GetRegistration(); reg != nil { - kid = reg.URI + kid = reg.Location } core, err := api.New(config.HTTPClient, config.UserAgent, config.CADirURL, kid, privateKey) diff --git a/lego/client_test.go b/lego/client_test.go index 1a367781d..e76d5899d 100644 --- a/lego/client_test.go +++ b/lego/client_test.go @@ -6,8 +6,8 @@ import ( "crypto/rsa" "testing" + "github.com/go-acme/lego/v5/acme" "github.com/go-acme/lego/v5/internal/tester" - "github.com/go-acme/lego/v5/registration" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -20,7 +20,7 @@ func TestNewClient(t *testing.T) { user := mockUser{ email: "test@test.com", - regres: new(registration.Resource), + regres: new(acme.ExtendedAccount), privatekey: key, } @@ -36,10 +36,10 @@ func TestNewClient(t *testing.T) { type mockUser struct { email string - regres *registration.Resource + regres *acme.ExtendedAccount privatekey *rsa.PrivateKey } -func (u mockUser) GetEmail() string { return u.email } -func (u mockUser) GetRegistration() *registration.Resource { return u.regres } -func (u mockUser) GetPrivateKey() crypto.PrivateKey { return u.privatekey } +func (u mockUser) GetEmail() string { return u.email } +func (u mockUser) GetRegistration() *acme.ExtendedAccount { return u.regres } +func (u mockUser) GetPrivateKey() crypto.PrivateKey { return u.privatekey } diff --git a/registration/registar.go b/registration/registar.go index 282f59e82..daf25c3ea 100644 --- a/registration/registar.go +++ b/registration/registar.go @@ -16,14 +16,6 @@ import ( const mailTo = "mailto:" -// Resource represents all important information about a registration -// of which the client needs to keep track itself. -// WARNING: will be removed in the future (acme.ExtendedAccount), https://github.com/go-acme/lego/issues/855. -type Resource struct { - Body acme.Account `json:"body"` - URI string `json:"uri,omitempty"` -} - type RegisterOptions struct { TermsOfServiceAgreed bool } @@ -47,7 +39,7 @@ func NewRegistrar(core *api.Core, user User) *Registrar { } // Register the current account to the ACME server. -func (r *Registrar) Register(ctx context.Context, options RegisterOptions) (*Resource, error) { +func (r *Registrar) Register(ctx context.Context, options RegisterOptions) (*acme.ExtendedAccount, error) { if r == nil || r.user == nil { return nil, errors.New("acme: cannot register a nil client or user") } @@ -59,6 +51,7 @@ func (r *Registrar) Register(ctx context.Context, options RegisterOptions) (*Res if r.user.GetEmail() != "" { log.Info("acme: Registering the account.", slog.String("email", r.user.GetEmail())) + accMsg.Contact = []string{mailTo + r.user.GetEmail()} } @@ -71,11 +64,11 @@ func (r *Registrar) Register(ctx context.Context, options RegisterOptions) (*Res } } - return &Resource{URI: account.Location, Body: account.Account}, nil + return &account, nil } // RegisterWithExternalAccountBinding Register the current account to the ACME server. -func (r *Registrar) RegisterWithExternalAccountBinding(ctx context.Context, options RegisterEABOptions) (*Resource, error) { +func (r *Registrar) RegisterWithExternalAccountBinding(ctx context.Context, options RegisterEABOptions) (*acme.ExtendedAccount, error) { accMsg := acme.Account{ TermsOfServiceAgreed: options.TermsOfServiceAgreed, Contact: []string{}, @@ -83,6 +76,7 @@ func (r *Registrar) RegisterWithExternalAccountBinding(ctx context.Context, opti if r.user.GetEmail() != "" { log.Info("acme: Registering the account.", slog.String("email", r.user.GetEmail())) + accMsg.Contact = []string{mailTo + r.user.GetEmail()} } @@ -95,35 +89,36 @@ func (r *Registrar) RegisterWithExternalAccountBinding(ctx context.Context, opti } } - return &Resource{URI: account.Location, Body: account.Account}, nil + return &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(ctx context.Context) (*Resource, error) { +func (r *Registrar) QueryRegistration(ctx context.Context) (*acme.ExtendedAccount, error) { if r == nil || r.user == nil || r.user.GetRegistration() == 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 - log.Info("acme: Querying the account.", slog.String("registrationURI", r.user.GetRegistration().URI)) + log.Info("acme: Querying the account.", slog.String("registrationURI", r.user.GetRegistration().Location)) - account, err := r.core.Accounts.Get(ctx, r.user.GetRegistration().URI) + account, err := r.core.Accounts.Get(ctx, r.user.GetRegistration().Location) 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, + return &acme.ExtendedAccount{ + Account: account, + + // Location: header is not returned, so this needs to be populated off of the existing URI + Location: r.user.GetRegistration().Location, }, nil } // UpdateRegistration update the user registration on the ACME server. -func (r *Registrar) UpdateRegistration(ctx context.Context, options RegisterOptions) (*Resource, error) { +func (r *Registrar) UpdateRegistration(ctx context.Context, options RegisterOptions) (*acme.ExtendedAccount, error) { if r == nil || r.user == nil { return nil, errors.New("acme: cannot update a nil client or user") } @@ -138,14 +133,14 @@ func (r *Registrar) UpdateRegistration(ctx context.Context, options RegisterOpti accMsg.Contact = []string{mailTo + r.user.GetEmail()} } - accountURL := r.user.GetRegistration().URI + accountURL := r.user.GetRegistration().Location account, err := r.core.Accounts.Update(ctx, accountURL, accMsg) if err != nil { return nil, err } - return &Resource{URI: accountURL, Body: account}, nil + return &acme.ExtendedAccount{Account: account, Location: accountURL}, nil } // DeleteRegistration deletes the client's user registration from the ACME server. @@ -156,12 +151,12 @@ func (r *Registrar) DeleteRegistration(ctx context.Context) error { log.Info("acme: Deleting the account.", slog.String("email", r.user.GetEmail())) - return r.core.Accounts.Deactivate(ctx, r.user.GetRegistration().URI) + return r.core.Accounts.Deactivate(ctx, r.user.GetRegistration().Location) } // ResolveAccountByKey will attempt to look up an account using the given account key // and return its registration resource. -func (r *Registrar) ResolveAccountByKey(ctx context.Context) (*Resource, error) { +func (r *Registrar) ResolveAccountByKey(ctx context.Context) (*acme.ExtendedAccount, error) { log.Info("acme: Trying to resolve the account by key") accMsg := acme.Account{OnlyReturnExisting: true} @@ -171,12 +166,12 @@ func (r *Registrar) ResolveAccountByKey(ctx context.Context) (*Resource, error) return nil, err } - return &Resource{URI: account.Location, Body: account.Account}, nil + return &account, nil } // RegisterWithZeroSSL registers the current account to the ZeroSSL. // It uses either an access key or an email to generate an EAB. -func RegisterWithZeroSSL(ctx context.Context, r *Registrar, email string) (*Resource, error) { +func RegisterWithZeroSSL(ctx context.Context, r *Registrar, email string) (*acme.ExtendedAccount, error) { zc := zerossl.NewClient() value, find := os.LookupEnv(zerossl.EnvZeroSSLAccessKey) diff --git a/registration/registar_test.go b/registration/registar_test.go index 47795a322..bef5ff420 100644 --- a/registration/registar_test.go +++ b/registration/registar_test.go @@ -31,7 +31,7 @@ func TestRegistrar_ResolveAccountByKey(t *testing.T) { user := mockUser{ email: "test@test.com", - regres: &Resource{}, + regres: &acme.ExtendedAccount{}, privatekey: key, } @@ -43,5 +43,5 @@ func TestRegistrar_ResolveAccountByKey(t *testing.T) { res, err := registrar.ResolveAccountByKey(t.Context()) require.NoError(t, err, "Unexpected error resolving account by key") - assert.Equal(t, "valid", res.Body.Status, "Unexpected account status") + assert.Equal(t, "valid", res.Status, "Unexpected account status") } diff --git a/registration/user.go b/registration/user.go index 1e29300e2..206638c79 100644 --- a/registration/user.go +++ b/registration/user.go @@ -2,12 +2,14 @@ package registration import ( "crypto" + + "github.com/go-acme/lego/v5/acme" ) // User interface is to be implemented by users of this library. // It is used by the client type to get user specific information. type User interface { GetEmail() string - GetRegistration() *Resource + GetRegistration() *acme.ExtendedAccount GetPrivateKey() crypto.PrivateKey } diff --git a/registration/user_test.go b/registration/user_test.go index b9c5de334..055cc814a 100644 --- a/registration/user_test.go +++ b/registration/user_test.go @@ -3,14 +3,16 @@ package registration import ( "crypto" "crypto/rsa" + + "github.com/go-acme/lego/v5/acme" ) type mockUser struct { email string - regres *Resource + regres *acme.ExtendedAccount privatekey *rsa.PrivateKey } -func (u mockUser) GetEmail() string { return u.email } -func (u mockUser) GetRegistration() *Resource { return u.regres } -func (u mockUser) GetPrivateKey() crypto.PrivateKey { return u.privatekey } +func (u mockUser) GetEmail() string { return u.email } +func (u mockUser) GetRegistration() *acme.ExtendedAccount { return u.regres } +func (u mockUser) GetPrivateKey() crypto.PrivateKey { return u.privatekey }