feat(website): Certificate application supports custom ACME addresses. (#8475)

This commit is contained in:
ChengPlay 2025-04-25 16:49:22 +08:00 committed by GitHub
parent f367a6eaaf
commit 46120a74ed
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 39 additions and 7 deletions

View file

@ -47,11 +47,12 @@ type WebsiteSSLApply struct {
type WebsiteAcmeAccountCreate struct {
Email string `json:"email" validate:"required"`
Type string `json:"type" validate:"required,oneof=letsencrypt zerossl buypass google freessl"`
Type string `json:"type" validate:"required,oneof=letsencrypt zerossl buypass google custom"`
KeyType string `json:"keyType" validate:"required,oneof=P256 P384 2048 3072 4096 8192"`
EabKid string `json:"eabKid"`
EabHmacKey string `json:"eabHmacKey"`
UseProxy bool `json:"useProxy"`
CaDirURL string `json:"caDirURL"`
}
type WebsiteAcmeAccountUpdate struct {

View file

@ -10,6 +10,7 @@ type WebsiteAcmeAccount struct {
EabHmacKey string `gorm:"default:null" json:"eabHmacKey"`
KeyType string `gorm:"not null;default:2048" json:"keyType"`
UseProxy bool `gorm:"default:false" json:"useProxy"`
CaDirURL string `gorm:"default:null" json:"caDirURL"`
}
func (w WebsiteAcmeAccount) TableName() string {

View file

@ -54,6 +54,9 @@ func (w WebsiteAcmeAccountService) Create(create request.WebsiteAcmeAccountCreat
acmeAccount.EabKid = create.EabKid
acmeAccount.EabHmacKey = create.EabHmacKey
}
if create.Type == "custom" && create.CaDirURL != "" {
acmeAccount.CaDirURL = create.CaDirURL
}
client, err := ssl.NewAcmeClient(acmeAccount, getSystemProxy(acmeAccount.UseProxy))
if err != nil {

View file

@ -348,7 +348,9 @@ func (w WebsiteSSLService) ObtainSSL(apply request.WebsiteSSLApply) error {
websiteSSL.ExpireDate = cert.NotAfter
websiteSSL.StartDate = cert.NotBefore
websiteSSL.Type = cert.Issuer.CommonName
websiteSSL.Organization = cert.Issuer.Organization[0]
if len(cert.Issuer.Organization) > 0 {
websiteSSL.Organization = cert.Issuer.Organization[0]
}
websiteSSL.Status = constant.SSLReady
printSSLLog(logger, "ApplySSLSuccess", map[string]interface{}{"domain": strings.Join(domains, ",")}, apply.DisableLog)
saveCertificateFile(websiteSSL, logger)

View file

@ -344,7 +344,7 @@ var UpdateWebsite = &gormigrate.Migration{
}
var UpdateWebsiteAcmeAccount = &gormigrate.Migration{
ID: "20250422-update-websiteAcmeAccount",
ID: "20250425-update-websiteAcmeAccount",
Migrate: func(tx *gorm.DB) error {
if err := tx.AutoMigrate(&model.WebsiteAcmeAccount{}); err != nil {
return err

View file

@ -109,7 +109,7 @@ func NewRegisterClient(acmeAccount *model.WebsiteAcmeAccount, proxy *dto.SystemP
Email: acmeAccount.Email,
Key: priKey,
}
config := NewConfigWithProxy(myUser, acmeAccount.Type, proxy)
config := NewConfigWithProxy(myUser, acmeAccount.Type, acmeAccount.CaDirURL, proxy)
client, err := lego.NewClient(config)
if err != nil {
return nil, err
@ -156,7 +156,7 @@ func NewRegisterClient(acmeAccount *model.WebsiteAcmeAccount, proxy *dto.SystemP
return acmeClient, nil
}
func NewConfigWithProxy(user registration.User, accountType string, systemProxy *dto.SystemProxy) *lego.Config {
func NewConfigWithProxy(user registration.User, accountType, customCaURL string, systemProxy *dto.SystemProxy) *lego.Config {
var (
caDirURL string
proxyURL string
@ -174,6 +174,8 @@ func NewConfigWithProxy(user registration.User, accountType string, systemProxy
caDirURL = "https://dv.acme-v02.api.pki.goog/directory"
case "freessl":
caDirURL = "https://acmepro.freessl.cn/v2/DV"
case "custom":
caDirURL = customCaURL
}
if systemProxy != nil {
proxyURL = fmt.Sprintf("%s:%s", systemProxy.URL, systemProxy.Port)
@ -241,8 +243,9 @@ func createHTTPClientWithProxy(proxyURL, username, password string) *http.Client
TLSHandshakeTimeout: 60 * time.Second,
ResponseHeaderTimeout: 60 * time.Second,
TLSClientConfig: &tls.Config{
ServerName: os.Getenv("LEGO_CA_SERVER_NAME"),
RootCAs: initCertPool(),
InsecureSkipVerify: true,
//ServerName: os.Getenv("LEGO_CA_SERVER_NAME"),
//RootCAs: initCertPool(),
},
},
}

View file

@ -152,6 +152,7 @@ export const AcmeAccountTypes = [
{ label: 'ZeroSSL', value: 'zerossl' },
{ label: 'Buypass', value: 'buypass' },
{ label: 'Google Cloud', value: 'google' },
{ label: i18n.global.t('ssl.customAcme'), value: 'custom' },
];
export const KeyTypes = [

View file

@ -2555,6 +2555,8 @@ const message = {
shell: 'Script content',
shellHelper:
'The default execution directory of the script is the 1Panel installation directory. If a certificate is pushed, the execution directory is the certificate push directory. The default timeout is 30 minutes',
customAcme: 'Custom ACME Service',
customAcmeURL: 'ACME Service URL',
},
firewall: {
create: 'Create Rule',

View file

@ -2445,6 +2445,8 @@ const message = {
shell: 'スクリプトコンテンツ',
shellHelper:
'スクリプトのデフォルトの実行ディレクトリは1Panelインストールディレクトリです証明書がローカルディレクトリにプッシュされた場合実行ディレクトリは証明書プッシュディレクトリになりますデフォルトの実行タイムアウトは30分です',
customAcme: 'カスタム ACME サービス',
customAcmeURL: 'ACME サービス URL',
},
firewall: {
create: 'ルールを作成します',

View file

@ -2404,6 +2404,8 @@ const message = {
shell: '스크립트 내용',
shellHelper:
'스크립트의 기본 실행 디렉토리는 1Panel 설치 디렉토리입니다. 인증서가 로컬 디렉토리에 푸시되는 경우 실행 디렉토리는 인증서 푸시 디렉토리가 됩니다. 기본 실행 제한 시간은 30분입니다.',
customAcme: '사용자 정의 ACME 서비스',
customAcmeURL: 'ACME 서비스 URL',
},
firewall: {
create: '규칙 만들기',

View file

@ -2501,6 +2501,8 @@ const message = {
shell: 'Kandungan skrip',
shellHelper:
'Direktori pelaksanaan lalai skrip adalah direktori pemasangan 1Panel. Jika sijil ditolak ke direktori tempatan, direktori pelaksanaan akan menjadi direktori tolak sijil. Tamat masa pelaksanaan lalai ialah 30 minit.',
customAcme: 'Perkhidmatan ACME Tersuai',
customAcmeURL: 'URL Perkhidmatan ACME',
},
firewall: {
create: 'Buat peraturan',

View file

@ -2498,6 +2498,8 @@ const message = {
shell: 'Conteúdo do script',
shellHelper:
'O diretório padrão de execução do script é o diretório de instalação do 1Panel. Se um certificado for enviado para o diretório local, o diretório de execução será o diretório de envio do certificado. O tempo limite padrão de execução é de 30 minutos.',
customAcme: 'Serviço ACME Personalizado',
customAcmeURL: 'URL do Serviço ACME',
},
firewall: {
create: 'Criar regra',

View file

@ -2497,6 +2497,8 @@ const message = {
shell: 'Содержимое скрипта',
shellHelper:
'Директория выполнения скрипта по умолчанию - директория установки 1Panel. Если сертификат отправляется в локальную директорию, директорией выполнения будет директория отправки сертификата. Тайм-аут выполнения по умолчанию - 30 минут.',
customAcme: 'Пользовательская служба ACME',
customAcmeURL: 'URL службы ACME',
},
firewall: {
create: 'Создать правило',

View file

@ -2372,6 +2372,8 @@ const message = {
shell: '腳本內容',
shellHelper:
'腳本預設執行目錄為 1Panel 安裝目錄如果有推送證書那麼執行目錄為證書推送目錄預設超時時間 30 分鐘',
customAcme: '自訂 ACME 服務',
customAcmeURL: 'ACME 服務 URL',
},
firewall: {
create: '創建規則',

View file

@ -2363,6 +2363,8 @@ const message = {
shell: '脚本内容',
shellHelper:
'脚本默认执行目录为 1Panel 安装目录如果有推送证书那么执行目录为证书推送目录默认超时时间 30 分钟',
customAcme: '自定义 ACME 服务',
customAcmeURL: 'ACME 服务 URL',
},
firewall: {
create: '创建规则',

View file

@ -55,6 +55,9 @@
{{ $t('ssl.googleHelper') }}
</el-link>
</div>
<el-form-item v-if="account.type == 'custom'" :label="$t('ssl.customAcmeURL')" prop="caDirURL">
<el-input v-model.trim="account.caDirURL"></el-input>
</el-form-item>
</el-form>
</el-col>
</el-row>
@ -86,6 +89,7 @@ const rules = ref({
eabKid: [Rules.requiredInput],
eabHmacKey: [Rules.requiredInput],
keyType: [Rules.requiredSelect],
caDirURL: [Rules.requiredInput],
});
const initData = () => ({
@ -95,6 +99,7 @@ const initData = () => ({
eabHmacKey: '',
keyType: 'P256',
useProxy: false,
caDirURL: '',
});
const account = ref(initData());