Skip to content

Commit

Permalink
feat: 添加GoogleCN证书
Browse files Browse the repository at this point in the history
  • Loading branch information
devhaozi committed Oct 12, 2024
1 parent 2978df4 commit 1ae8011
Show file tree
Hide file tree
Showing 9 changed files with 104 additions and 84 deletions.
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down Expand Up @@ -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=
Expand Down
9 changes: 6 additions & 3 deletions internal/data/cert.go
Original file line number Diff line number Diff line change
Expand Up @@ -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":
Expand All @@ -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)
Expand Down
48 changes: 43 additions & 5 deletions internal/data/cert_account.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package data
import (
"context"
"errors"
"fmt"
"time"

"github.com/go-resty/resty/v2"
Expand Down Expand Up @@ -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":
Expand All @@ -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)
Expand Down Expand Up @@ -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":
Expand All @@ -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 提供商不支持")
}
Expand All @@ -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 {
Expand Down
63 changes: 34 additions & 29 deletions internal/service/cert.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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),
},
})

Expand Down
3 changes: 2 additions & 1 deletion pkg/acme/acme.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand Down
45 changes: 13 additions & 32 deletions web/src/views/cert/AccountView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,23 @@ const addAccountModel = ref<any>({
email: '',
kid: '',
key_type: 'P256',
ca: 'letsencrypt'
ca: 'googlecn'
})
const updateAccountModel = ref<any>({
hmac_encoded: '',
email: '',
kid: '',
key_type: 'P256',
ca: 'letsencrypt'
ca: 'googlecn'
})
const addAccountModal = ref(false)
const updateAccountModal = ref(false)
const updateAccount = ref<any>()
const showEAB = computed(() => {
return addAccountModel.value.ca === 'google' || addAccountModel.value.ca === 'sslcom'
})
const caProviders = ref<any>([])
const algorithms = ref<any>([])
Expand All @@ -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
}
}
)
Expand Down Expand Up @@ -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)
})
Expand Down Expand Up @@ -243,7 +224,7 @@ onMounted(() => {
<n-space vertical>
<n-alert type="info"> Google 和 SSL.com 需要先去官网获得 KID 和 HMAC 并填入 </n-alert>
<n-alert type="warning">
境内无法使用 Google CA,其他 CA 视网络情况而定,建议使用 Let's Encrypt
境内无法使用 Google,其他 CA 视网络情况而定,建议使用 GoogleCN 或 Let's Encrypt
</n-alert>
<n-form :model="addAccountModel">
<n-form-item path="ca" label="CA">
Expand All @@ -270,15 +251,15 @@ onMounted(() => {
placeholder="输入邮箱地址"
/>
</n-form-item>
<n-form-item path="kid" label="KID">
<n-form-item v-if="showEAB" path="kid" label="KID">
<n-input
v-model:value="addAccountModel.kid"
type="text"
@keydown.enter.prevent
placeholder="输入 KID"
/>
</n-form-item>
<n-form-item path="hmac_encoded" label="HMAC">
<n-form-item v-if="showEAB" path="hmac_encoded" label="HMAC">
<n-input
v-model:value="addAccountModel.hmac_encoded"
type="text"
Expand All @@ -302,7 +283,7 @@ onMounted(() => {
<n-space vertical>
<n-alert type="info"> Google 和 SSL.com 需要先去官网获得 KID 和 HMAC 并填入 </n-alert>
<n-alert type="warning">
境内无法使用 Google CA,其他 CA 视网络情况而定,建议使用 Let's Encrypt
境内无法使用 Google,其他 CA 视网络情况而定,建议使用 GoogleCN 或 Let's Encrypt
</n-alert>
<n-form :model="updateAccountModel">
<n-form-item path="ca" label="CA">
Expand Down
7 changes: 1 addition & 6 deletions web/src/views/cert/CertView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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 = []
Expand Down
Loading

0 comments on commit 1ae8011

Please sign in to comment.