diff --git a/app/http/requests/cert/user_store.go b/app/http/requests/cert/user_store.go index bb7e1585..06335266 100644 --- a/app/http/requests/cert/user_store.go +++ b/app/http/requests/cert/user_store.go @@ -21,8 +21,8 @@ func (r *UserStore) Rules(ctx http.Context) map[string]string { return map[string]string{ "ca": "required|in:letsencrypt,zerossl,sslcom,google,buypass", "email": "required|email", - "kid": "required_unless:ca,letsencrypt,buypass", - "hmac_encoded": "required_unless:ca,letsencrypt,buypass", + "kid": "required_if:ca,sslcom,google", + "hmac_encoded": "required_if:ca,sslcom,google", "key_type": "required|in:P256,P384,2048,4096", } } diff --git a/app/http/requests/cert/user_update.go b/app/http/requests/cert/user_update.go index 3f39a6d2..055b7efc 100644 --- a/app/http/requests/cert/user_update.go +++ b/app/http/requests/cert/user_update.go @@ -23,8 +23,8 @@ func (r *UserUpdate) Rules(ctx http.Context) map[string]string { "id": "required|uint|min:1|exists:cert_users,id", "ca": "required|in:letsencrypt,zerossl,sslcom,google,buypass", "email": "required|email", - "kid": "required_unless:ca,letsencrypt,buypass", - "hmac_encoded": "required_unless:ca,letsencrypt,buypass", + "kid": "required_if:ca,sslcom,google", + "hmac_encoded": "required_if:ca,sslcom,google", "key_type": "required|in:P256,P384,2048,4096", } } diff --git a/internal/services/cert.go b/internal/services/cert.go index 7926b0ca..d98ceea9 100644 --- a/internal/services/cert.go +++ b/internal/services/cert.go @@ -8,6 +8,7 @@ import ( "strings" "time" + "github.com/go-resty/resty/v2" "github.com/goravel/framework/facades" requests "github.com/TheTNB/panel/app/http/requests/cert" @@ -43,7 +44,11 @@ func (s *CertImpl) UserStore(request requests.UserStore) error { case "buypass": client, err = acme.NewRegisterAccount(context.Background(), user.Email, acme.CABuypass, nil, acme.KeyType(user.KeyType)) case "zerossl": - client, err = acme.NewRegisterAccount(context.Background(), user.Email, acme.CAZeroSSL, &acme.EAB{KeyID: user.Kid, MACKey: user.HmacEncoded}, acme.KeyType(user.KeyType)) + eab, err := s.getZeroSSLEAB(user.Email) + if err != nil { + return err + } + client, err = acme.NewRegisterAccount(context.Background(), user.Email, acme.CAZeroSSL, eab, acme.KeyType(user.KeyType)) case "sslcom": client, err = acme.NewRegisterAccount(context.Background(), user.Email, acme.CASSLcom, &acme.EAB{KeyID: user.Kid, MACKey: user.HmacEncoded}, acme.KeyType(user.KeyType)) case "google": @@ -86,7 +91,11 @@ func (s *CertImpl) UserUpdate(request requests.UserUpdate) error { case "buypass": client, err = acme.NewRegisterAccount(context.Background(), user.Email, acme.CABuypass, nil, acme.KeyType(user.KeyType)) case "zerossl": - client, err = acme.NewRegisterAccount(context.Background(), user.Email, acme.CAZeroSSL, &acme.EAB{KeyID: user.Kid, MACKey: user.HmacEncoded}, acme.KeyType(user.KeyType)) + eab, err := s.getZeroSSLEAB(user.Email) + if err != nil { + return err + } + client, err = acme.NewRegisterAccount(context.Background(), user.Email, acme.CAZeroSSL, eab, acme.KeyType(user.KeyType)) case "sslcom": client, err = acme.NewRegisterAccount(context.Background(), user.Email, acme.CASSLcom, &acme.EAB{KeyID: user.Kid, MACKey: user.HmacEncoded}, acme.KeyType(user.KeyType)) case "google": @@ -108,6 +117,31 @@ func (s *CertImpl) UserUpdate(request requests.UserUpdate) error { return facades.Orm().Query().Save(&user) } +// getZeroSSLEAB 获取 ZeroSSL EAB +func (s *CertImpl) getZeroSSLEAB(email string) (*acme.EAB, error) { + type data struct { + Success bool `json:"success"` + EabKid string `json:"eab_kid"` + EabHmacKey string `json:"eab_hmac_key"` + } + client := resty.New() + client.SetTimeout(5 * time.Second) + client.SetRetryCount(2) + + resp, err := client.R().SetFormData(map[string]string{ + "email": email, + }).SetResult(&data{}).Post("https://api.zerossl.com/acme/eab-credentials-email") + if err != nil || !resp.IsSuccess() { + return &acme.EAB{}, errors.New("获取ZeroSSL EAB失败") + } + eab := resp.Result().(*data) + if !eab.Success { + return &acme.EAB{}, errors.New("获取ZeroSSL EAB失败") + } + + return &acme.EAB{KeyID: eab.EabKid, MACKey: eab.EabHmacKey}, nil +} + // UserShow 根据 ID 获取用户 func (s *CertImpl) UserShow(ID uint) (models.CertUser, error) { var user models.CertUser