package acme import ( "context" "crypto" "crypto/ecdsa" "crypto/elliptic" "crypto/rand" "crypto/rsa" "errors" "log/slog" "net/http" "github.com/mholt/acmez/v3" "github.com/mholt/acmez/v3/acme" "github.com/acepanel/panel/pkg/cert" ) const ( CAGoogleCN = "https://gts.rat.dev/directory" CAGoogle = "https://dv.acme-v02.api.pki.goog/directory" CALetsEncryptStaging = "https://acme-staging-v02.api.letsencrypt.org/directory" CALetsEncrypt = "https://acme-v02.api.letsencrypt.org/directory" CAZeroSSL = "https://acme.zerossl.com/v2/DV90" CABuypass = "https://api.buypass.com/acme/directory" CASSLcom = "https://acme.ssl.com/sslcom-dv-rsa" ) type KeyType string const ( KeyEC256 = KeyType("P256") KeyEC384 = KeyType("P384") KeyRSA2048 = KeyType("2048") KeyRSA3072 = KeyType("3072") KeyRSA4096 = KeyType("4096") ) type EAB = acme.EAB func NewRegisterAccount(ctx context.Context, email, CA string, eab *EAB, keyType KeyType, log *slog.Logger) (*Client, error) { client, err := getClient(CA, log) if err != nil { return nil, err } accountPrivateKey, err := generatePrivateKey(keyType) if err != nil { return nil, err } account := acme.Account{ Contact: []string{"mailto:" + email}, TermsOfServiceAgreed: true, PrivateKey: accountPrivateKey, } if eab != nil { err = account.SetExternalAccountBinding(ctx, client.Client, *eab) if err != nil { return nil, err } } account, err = client.NewAccount(ctx, account) if err != nil { return nil, err } return &Client{Account: account, zClient: client}, nil } func NewPrivateKeyAccount(email string, privateKey string, CA string, eab *EAB, log *slog.Logger) (*Client, error) { client, err := getClient(CA, log) if err != nil { return nil, err } key, err := cert.ParseKey(privateKey) if err != nil { return nil, err } account := acme.Account{ Contact: []string{"mailto:" + email}, TermsOfServiceAgreed: true, PrivateKey: key, } if eab != nil { err = account.SetExternalAccountBinding(context.Background(), client.Client, *eab) if err != nil { return nil, err } } account, err = client.GetAccount(context.Background(), account) if err != nil { return nil, err } return &Client{Account: account, zClient: client}, nil } func generatePrivateKey(keyType KeyType) (crypto.Signer, error) { switch keyType { case KeyEC256: return ecdsa.GenerateKey(elliptic.P256(), rand.Reader) case KeyEC384: return ecdsa.GenerateKey(elliptic.P384(), rand.Reader) case KeyRSA2048: return rsa.GenerateKey(rand.Reader, 2048) case KeyRSA3072: return rsa.GenerateKey(rand.Reader, 3072) case KeyRSA4096: return rsa.GenerateKey(rand.Reader, 4096) } return nil, errors.New("unsupported key type") } func getClient(CA string, log *slog.Logger) (acmez.Client, error) { client := acmez.Client{ Client: &acme.Client{ Directory: CA, HTTPClient: http.DefaultClient, Logger: log, }, } return client, nil }