MCPcopy
hub / github.com/caddyserver/certmagic / newACMEClientWithAccount

Method newACMEClientWithAccount

acmeclient.go:48–166  ·  view source on GitHub ↗

newACMEClientWithAccount creates an ACME client ready to use with an account, including loading one from storage or registering a new account with the CA if necessary. If useTestCA is true, am.TestCA will be used if set; otherwise, the primary CA will be used.

(ctx context.Context, useTestCA, interactive bool)

Source from the content-addressed store, hash-verified

46// loading one from storage or registering a new account with the CA if necessary. If
47// useTestCA is true, am.TestCA will be used if set; otherwise, the primary CA will be used.
48func (iss *ACMEIssuer) newACMEClientWithAccount(ctx context.Context, useTestCA, interactive bool) (*acmeClient, error) {
49 // first, get underlying ACME client
50 client, err := iss.newACMEClient(useTestCA)
51 if err != nil {
52 return nil, err
53 }
54
55 // we try loading the account from storage before a potential
56 // lock, and after obtaining the lock as well, to ensure we don't
57 // repeat work done by another instance or goroutine
58 account, err := iss.getAccountToUse(ctx, client.Directory)
59 if err != nil {
60 return nil, err
61 }
62
63 // register account if it is new
64 if account.Status == "" {
65 iss.Logger.Info("ACME account has empty status; registering account with ACME server",
66 zap.Strings("contact", account.Contact),
67 zap.String("location", account.Location))
68
69 // synchronize this so the account is only created once
70 acctLockKey := accountRegLockKey(account)
71 err = acquireLock(ctx, iss.config.Storage, acctLockKey)
72 if err != nil {
73 return nil, fmt.Errorf("locking account registration: %v", err)
74 }
75 defer func() {
76 if err := releaseLock(ctx, iss.config.Storage, acctLockKey); err != nil {
77 iss.Logger.Error("failed to unlock account registration lock", zap.Error(err))
78 }
79 }()
80
81 // if we're not the only one waiting for this account, then by this point it should already be registered and in storage; reload it
82 account, err = iss.getAccountToUse(ctx, client.Directory)
83 if err != nil {
84 return nil, err
85 }
86
87 // if we are the only or first one waiting for this account, then proceed to register it while we have the lock
88 if account.Status == "" {
89 if iss.NewAccountFunc != nil {
90 // obtain lock here, since NewAccountFunc calls happen concurrently and they typically read and change the issuer
91 iss.mu.Lock()
92 account, err = iss.NewAccountFunc(ctx, iss, account)
93 iss.mu.Unlock()
94 if err != nil {
95 return nil, fmt.Errorf("account pre-registration callback: %v", err)
96 }
97 }
98
99 // agree to terms
100 if interactive {
101 if !iss.isAgreed() {
102 var termsURL string
103 dir, err := client.GetDirectory(ctx)
104 if err != nil {
105 return nil, fmt.Errorf("getting directory: %w", err)

Callers 2

doIssueMethod · 0.95
RevokeMethod · 0.95

Calls 12

newACMEClientMethod · 0.95
getAccountToUseMethod · 0.95
isAgreedMethod · 0.95
askUserAgreementMethod · 0.95
saveAccountMethod · 0.95
accountRegLockKeyFunction · 0.85
acquireLockFunction · 0.85
releaseLockFunction · 0.85
StringMethod · 0.80
ErrorMethod · 0.80
LockMethod · 0.65
UnlockMethod · 0.65

Tested by

no test coverage detected