diff --git a/go.mod b/go.mod index b671e08e..4a3425cd 100644 --- a/go.mod +++ b/go.mod @@ -130,3 +130,5 @@ require ( modernc.org/memory v1.8.0 // indirect modernc.org/sqlite v1.32.0 // indirect ) + +replace github.com/mholt/acmez/v2 => github.com/TheTNB/acmez/v2 v2.0.0-20241012154227-1911c2ed4ae4 diff --git a/go.sum b/go.sum index 98bd8d4b..44729420 100644 --- a/go.sum +++ b/go.sum @@ -23,6 +23,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU= github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA= +github.com/TheTNB/acmez/v2 v2.0.0-20241012154227-1911c2ed4ae4 h1:pQyd4C3Y8MuvvJ0B3d4hDHQpLe2Bb/dW7/GwcIoyCSY= +github.com/TheTNB/acmez/v2 v2.0.0-20241012154227-1911c2ed4ae4/go.mod h1:pQ1ysaDeGrIMvJ9dfJMk5kJNkn7L2sb3UhyrX6Q91cw= github.com/andybalholm/brotli v1.0.4 h1:V7DdXeJtZscaqfNuAdSRuRFzuiKlHSC/Zh3zl9qY3JY= github.com/andybalholm/brotli v1.0.4/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig= github.com/beevik/ntp v1.4.3 h1:PlbTvE5NNy4QHmA4Mg57n7mcFTmr1W1j3gcK7L1lqho= @@ -227,8 +229,6 @@ github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/mholt/acmez/v2 v2.0.3 h1:CgDBlEwg3QBp6s45tPQmFIBrkRIkBT4rW4orMM6p4sw= -github.com/mholt/acmez/v2 v2.0.3/go.mod h1:pQ1ysaDeGrIMvJ9dfJMk5kJNkn7L2sb3UhyrX6Q91cw= github.com/mholt/archiver/v4 v4.0.0-alpha.8 h1:tRGQuDVPh66WCOelqe6LIGh0gwmfwxUrSSDunscGsRM= github.com/mholt/archiver/v4 v4.0.0-alpha.8/go.mod h1:5f7FUYGXdJWUjESffJaYR4R60VhnHxb2X3T1teMyv5A= github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= diff --git a/internal/data/cert.go b/internal/data/cert.go index 77d9bba0..acef83ed 100644 --- a/internal/data/cert.go +++ b/internal/data/cert.go @@ -254,6 +254,12 @@ func (r *certRepo) getClient(cert *biz.Cert) (*acme.Client, error) { var ca string var eab *acme.EAB switch cert.Account.CA { + case "googlecn": + ca = acme.CAGoogleCN + eab = &acme.EAB{KeyID: cert.Account.Kid, MACKey: cert.Account.HmacEncoded} + case "google": + ca = acme.CAGoogle + eab = &acme.EAB{KeyID: cert.Account.Kid, MACKey: cert.Account.HmacEncoded} case "letsencrypt": ca = acme.CALetsEncrypt case "buypass": @@ -264,9 +270,6 @@ func (r *certRepo) getClient(cert *biz.Cert) (*acme.Client, error) { case "sslcom": ca = acme.CASSLcom eab = &acme.EAB{KeyID: cert.Account.Kid, MACKey: cert.Account.HmacEncoded} - case "google": - ca = acme.CAGoogle - eab = &acme.EAB{KeyID: cert.Account.Kid, MACKey: cert.Account.HmacEncoded} } return acme.NewPrivateKeyAccount(cert.Account.Email, cert.Account.PrivateKey, ca, eab) diff --git a/internal/data/cert_account.go b/internal/data/cert_account.go index d43e5e0b..e26cb7ea 100644 --- a/internal/data/cert_account.go +++ b/internal/data/cert_account.go @@ -3,6 +3,7 @@ package data import ( "context" "errors" + "fmt" "time" "github.com/go-resty/resty/v2" @@ -44,6 +45,14 @@ func (r certAccountRepo) Create(req *request.CertAccountCreate) (*biz.CertAccoun var err error var client *acme.Client switch account.CA { + case "googlecn": + eab, eabErr := r.getGoogleEAB() + if eabErr != nil { + return nil, eabErr + } + client, err = acme.NewRegisterAccount(context.Background(), account.Email, acme.CAGoogleCN, eab, acme.KeyType(account.KeyType)) + case "google": + client, err = acme.NewRegisterAccount(context.Background(), account.Email, acme.CAGoogle, &acme.EAB{KeyID: account.Kid, MACKey: account.HmacEncoded}, acme.KeyType(account.KeyType)) case "letsencrypt": client, err = acme.NewRegisterAccount(context.Background(), account.Email, acme.CALetsEncrypt, nil, acme.KeyType(account.KeyType)) case "buypass": @@ -56,14 +65,12 @@ func (r certAccountRepo) Create(req *request.CertAccountCreate) (*biz.CertAccoun client, err = acme.NewRegisterAccount(context.Background(), account.Email, acme.CAZeroSSL, eab, acme.KeyType(account.KeyType)) case "sslcom": client, err = acme.NewRegisterAccount(context.Background(), account.Email, acme.CASSLcom, &acme.EAB{KeyID: account.Kid, MACKey: account.HmacEncoded}, acme.KeyType(account.KeyType)) - case "google": - client, err = acme.NewRegisterAccount(context.Background(), account.Email, acme.CAGoogle, &acme.EAB{KeyID: account.Kid, MACKey: account.HmacEncoded}, acme.KeyType(account.KeyType)) default: return nil, errors.New("CA 提供商不支持") } if err != nil { - return nil, errors.New("向 CA 注册账号失败,请检查参数是否正确") + return nil, fmt.Errorf("注册账号失败:%v", err) } privateKey, err := cert.EncodeKey(client.Account.PrivateKey) @@ -93,6 +100,14 @@ func (r certAccountRepo) Update(req *request.CertAccountUpdate) error { var client *acme.Client switch account.CA { + case "googlecn": + eab, eabErr := r.getGoogleEAB() + if eabErr != nil { + return eabErr + } + client, err = acme.NewRegisterAccount(context.Background(), account.Email, acme.CAGoogleCN, eab, acme.KeyType(account.KeyType)) + case "google": + client, err = acme.NewRegisterAccount(context.Background(), account.Email, acme.CAGoogle, &acme.EAB{KeyID: account.Kid, MACKey: account.HmacEncoded}, acme.KeyType(account.KeyType)) case "letsencrypt": client, err = acme.NewRegisterAccount(context.Background(), account.Email, acme.CALetsEncrypt, nil, acme.KeyType(account.KeyType)) case "buypass": @@ -105,8 +120,6 @@ func (r certAccountRepo) Update(req *request.CertAccountUpdate) error { client, err = acme.NewRegisterAccount(context.Background(), account.Email, acme.CAZeroSSL, eab, acme.KeyType(account.KeyType)) case "sslcom": client, err = acme.NewRegisterAccount(context.Background(), account.Email, acme.CASSLcom, &acme.EAB{KeyID: account.Kid, MACKey: account.HmacEncoded}, acme.KeyType(account.KeyType)) - case "google": - client, err = acme.NewRegisterAccount(context.Background(), account.Email, acme.CAGoogle, &acme.EAB{KeyID: account.Kid, MACKey: account.HmacEncoded}, acme.KeyType(account.KeyType)) default: return errors.New("CA 提供商不支持") } @@ -128,6 +141,31 @@ func (r certAccountRepo) Delete(id uint) error { return app.Orm.Model(&biz.CertAccount{}).Where("id = ?", id).Delete(&biz.CertAccount{}).Error } +// getGoogleEAB 获取 Google EAB +func (r certAccountRepo) getGoogleEAB() (*acme.EAB, error) { + type data struct { + Message string `json:"message"` + Data struct { + KeyId string `json:"key_id"` + MacKey string `json:"mac_key"` + } `json:"data"` + } + client := resty.New() + client.SetTimeout(5 * time.Second) + client.SetRetryCount(2) + + resp, err := client.R().SetResult(&data{}).Get("https://panel.haozi.net/api/acme/googleEAB") + if err != nil || !resp.IsSuccess() { + return &acme.EAB{}, errors.New("获取Google EAB失败") + } + eab := resp.Result().(*data) + if eab.Message != "success" { + return &acme.EAB{}, errors.New("获取Google EAB失败") + } + + return &acme.EAB{KeyID: eab.Data.KeyId, MACKey: eab.Data.MacKey}, nil +} + // getZeroSSLEAB 获取 ZeroSSL EAB func (r certAccountRepo) getZeroSSLEAB(email string) (*acme.EAB, error) { type data struct { diff --git a/internal/service/cert.go b/internal/service/cert.go index 7d768971..f7b416a7 100644 --- a/internal/service/cert.go +++ b/internal/service/cert.go @@ -9,6 +9,7 @@ import ( "github.com/TheTNB/panel/internal/data" "github.com/TheTNB/panel/internal/http/request" "github.com/TheTNB/panel/pkg/acme" + "github.com/TheTNB/panel/pkg/types" ) type CertService struct { @@ -22,70 +23,74 @@ func NewCertService() *CertService { } func (s *CertService) CAProviders(w http.ResponseWriter, r *http.Request) { - Success(w, []map[string]string{ + Success(w, []types.LV{ { - "name": "Let's Encrypt", - "ca": "letsencrypt", + Label: "GoogleCN(推荐)", + Value: "googlecn", }, { - "name": "ZeroSSL", - "ca": "zerossl", + Label: "Let's Encrypt", + Value: "letsencrypt", }, { - "name": "SSL.com", - "ca": "sslcom", + Label: "ZeroSSL", + Value: "zerossl", }, { - "name": "Google", - "ca": "google", + Label: "SSL.com", + Value: "sslcom", }, { - "name": "Buypass", - "ca": "buypass", + Label: "Google", + Value: "google", + }, + { + Label: "Buypass", + Value: "buypass", }, }) } func (s *CertService) DNSProviders(w http.ResponseWriter, r *http.Request) { - Success(w, []map[string]any{ + Success(w, []types.LV{ { - "name": "DNSPod", - "dns": acme.DnsPod, + Label: "DNSPod", + Value: string(acme.DnsPod), }, { - "name": "腾讯云", - "dns": acme.Tencent, + Label: "腾讯云", + Value: string(acme.Tencent), }, { - "name": "阿里云", - "dns": acme.AliYun, + Label: "阿里云", + Value: string(acme.AliYun), }, { - "name": "CloudFlare", - "dns": acme.CloudFlare, + Label: "CloudFlare", + Value: string(acme.CloudFlare), }, }) } func (s *CertService) Algorithms(w http.ResponseWriter, r *http.Request) { - Success(w, []map[string]any{ + Success(w, []types.LV{ { - "name": "EC256", - "key": acme.KeyEC256, + Label: "EC256", + Value: string(acme.KeyEC256), }, { - "name": "EC384", - "key": acme.KeyEC384, + Label: "EC384", + Value: string(acme.KeyEC384), }, { - "name": "RSA2048", - "key": acme.KeyRSA2048, + Label: "RSA2048", + Value: string(acme.KeyRSA2048), }, { - "name": "RSA4096", - "key": acme.KeyRSA4096, + Label: "RSA4096", + Value: string(acme.KeyRSA4096), }, }) diff --git a/pkg/acme/acme.go b/pkg/acme/acme.go index 4cf6629b..79b482a7 100644 --- a/pkg/acme/acme.go +++ b/pkg/acme/acme.go @@ -17,10 +17,11 @@ import ( ) const ( + CAGoogleCN = "https://panel.haozi.net/api/acme/google/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" - CAGoogle = "https://dv.acme-v02.api.pki.goog/directory" CABuypass = "https://api.buypass.com/acme/directory" CASSLcom = "https://acme.ssl.com/sslcom-dv-rsa" ) diff --git a/web/src/views/cert/AccountView.vue b/web/src/views/cert/AccountView.vue index adbc8cb3..97613c10 100644 --- a/web/src/views/cert/AccountView.vue +++ b/web/src/views/cert/AccountView.vue @@ -18,19 +18,23 @@ const addAccountModel = ref({ email: '', kid: '', key_type: 'P256', - ca: 'letsencrypt' + ca: 'googlecn' }) const updateAccountModel = ref({ hmac_encoded: '', email: '', kid: '', key_type: 'P256', - ca: 'letsencrypt' + ca: 'googlecn' }) const addAccountModal = ref(false) const updateAccountModal = ref(false) const updateAccount = ref() +const showEAB = computed(() => { + return addAccountModel.value.ca === 'google' || addAccountModel.value.ca === 'sslcom' +}) + const caProviders = ref([]) const algorithms = ref([]) @@ -51,20 +55,7 @@ const accountColumns: any = [ }, { default: () => { - switch (row.ca) { - case 'letsencrypt': - return "Let's Encrypt" - case 'zerossl': - return 'ZeroSSL' - case 'sslcom': - return 'SSL.com' - case 'buypass': - return 'Buypass' - case 'google': - return 'Google' - default: - return '未知' - } + return caProviders.value.find((item: any) => item.value === row.ca)?.label } } ) @@ -192,20 +183,10 @@ const handleUpdateAccount = async () => { onMounted(() => { cert.caProviders().then((res) => { - for (const item of res.data) { - caProviders.value.push({ - label: item.name, - value: item.ca - }) - } + caProviders.value = res.data }) cert.algorithms().then((res) => { - for (const item of res.data) { - algorithms.value.push({ - label: item.name, - value: item.key - }) - } + algorithms.value = res.data }) onAccountPageChange(1) }) @@ -243,7 +224,7 @@ onMounted(() => { Google 和 SSL.com 需要先去官网获得 KID 和 HMAC 并填入 - 境内无法使用 Google CA,其他 CA 视网络情况而定,建议使用 Let's Encrypt + 境内无法使用 Google,其他 CA 视网络情况而定,建议使用 GoogleCN 或 Let's Encrypt @@ -270,7 +251,7 @@ onMounted(() => { placeholder="输入邮箱地址" /> - + { placeholder="输入 KID" /> - + { Google 和 SSL.com 需要先去官网获得 KID 和 HMAC 并填入 - 境内无法使用 Google CA,其他 CA 视网络情况而定,建议使用 Let's Encrypt + 境内无法使用 Google,其他 CA 视网络情况而定,建议使用 GoogleCN 或 Let's Encrypt diff --git a/web/src/views/cert/CertView.vue b/web/src/views/cert/CertView.vue index 1c5c576b..de41168e 100644 --- a/web/src/views/cert/CertView.vue +++ b/web/src/views/cert/CertView.vue @@ -426,12 +426,7 @@ const handleDeployCert = async () => { const getAsyncData = async () => { const { data: algorithmData } = await cert.algorithms() - for (const item of algorithmData) { - algorithms.value.push({ - label: item.name, - value: item.key - }) - } + algorithms.value = algorithmData const { data: websiteData } = await website.list(1, 10000) websites.value = [] diff --git a/web/src/views/cert/DnsView.vue b/web/src/views/cert/DnsView.vue index 63b841f0..8507b16f 100644 --- a/web/src/views/cert/DnsView.vue +++ b/web/src/views/cert/DnsView.vue @@ -187,12 +187,7 @@ const handleUpdateDNS = async () => { onMounted(async () => { cert.dnsProviders().then((res) => { - for (const item of res.data) { - dnsProviders.value.push({ - label: item.name, - value: item.dns - }) - } + dnsProviders.value = res.data }) onDnsPageChange(1) })