feat: configurable cert key type #264

This commit is contained in:
Jacky 2024-02-13 14:15:02 +08:00
parent a095c88fd2
commit 22d62e420b
12 changed files with 115 additions and 28 deletions

View file

@ -7,6 +7,7 @@ import (
"github.com/0xJacky/Nginx-UI/model"
"github.com/0xJacky/Nginx-UI/query"
"github.com/gin-gonic/gin"
"github.com/go-acme/lego/v4/certcrypto"
"github.com/spf13/cast"
"net/http"
"os"
@ -76,13 +77,14 @@ func GetCert(c *gin.Context) {
}
type certJson struct {
Name string `json:"name" binding:"required"`
SSLCertificatePath string `json:"ssl_certificate_path" binding:"required,certificate_path"`
SSLCertificateKeyPath string `json:"ssl_certificate_key_path" binding:"required,privatekey_path"`
SSLCertificate string `json:"ssl_certificate" binding:"omitempty,certificate"`
SSLCertificateKey string `json:"ssl_certificate_key" binding:"omitempty,privatekey"`
ChallengeMethod string `json:"challenge_method"`
DnsCredentialID int `json:"dns_credential_id"`
Name string `json:"name" binding:"required"`
SSLCertificatePath string `json:"ssl_certificate_path" binding:"required,certificate_path"`
SSLCertificateKeyPath string `json:"ssl_certificate_key_path" binding:"required,privatekey_path"`
SSLCertificate string `json:"ssl_certificate" binding:"omitempty,certificate"`
SSLCertificateKey string `json:"ssl_certificate_key" binding:"omitempty,privatekey"`
KeyType certcrypto.KeyType `json:"key_type" binding:"omitempty,auto_cert_key_type"`
ChallengeMethod string `json:"challenge_method"`
DnsCredentialID int `json:"dns_credential_id"`
}
func AddCert(c *gin.Context) {
@ -96,6 +98,7 @@ func AddCert(c *gin.Context) {
Name: json.Name,
SSLCertificatePath: json.SSLCertificatePath,
SSLCertificateKeyPath: json.SSLCertificateKeyPath,
KeyType: json.KeyType,
ChallengeMethod: json.ChallengeMethod,
DnsCredentialID: json.DnsCredentialID,
}
@ -146,6 +149,7 @@ func ModifyCert(c *gin.Context) {
SSLCertificatePath: json.SSLCertificatePath,
SSLCertificateKeyPath: json.SSLCertificateKeyPath,
ChallengeMethod: json.ChallengeMethod,
KeyType: json.KeyType,
DnsCredentialID: json.DnsCredentialID,
})

View file

@ -122,6 +122,7 @@ func IssueCert(c *gin.Context) {
SSLCertificatePath: sslCertificatePath,
SSLCertificateKeyPath: sslCertificateKeyPath,
AutoCert: model.AutoCertEnabled,
KeyType: payload.KeyType,
})
if err != nil {

View file

@ -14,6 +14,7 @@ export interface Cert extends ModelBase {
challenge_method: string
dns_credential_id: number
dns_credential?: DnsCredential
key_type: string
log: string
certificate_info: CertificateInfo
}

View file

@ -21,7 +21,7 @@ const data = inject('data') as Ref<Cert>
const issueCert = () => {
modalVisible.value = true
refObtainCertLive.value.issue_cert(data.value.name, data.value.domains).then(() => {
refObtainCertLive.value.issue_cert(data.value.name, data.value.domains, data.value.key_type).then(() => {
message.success($gettext('Renew successfully'))
emit('renewed')
})

View file

@ -44,10 +44,12 @@ const issueCert = () => {
step.value++
modalVisible.value = true
refObtainCertLive.value.issue_cert(computedDomain.value, [computedDomain.value, domain.value]).then(() => {
message.success($gettext('Renew successfully'))
emit('issued')
})
refObtainCertLive.value.issue_cert(computedDomain.value,
[computedDomain.value, domain.value])
.then(() => {
message.success($gettext('Renew successfully'))
emit('issued')
})
}
</script>

View file

@ -3,6 +3,7 @@ import { useGettext } from 'vue3-gettext'
import type { Ref } from 'vue'
import type { DnsChallenge } from '@/api/auto_cert'
import DNSChallenge from '@/views/domain/cert/components/DNSChallenge.vue'
import type { Cert } from '@/api/cert'
defineProps<{
hideNote?: boolean
@ -13,7 +14,39 @@ const { $gettext } = useGettext()
const no_server_name = inject('no_server_name')
// Provide by ObtainCert.vue
const data = inject('data') as Ref<DnsChallenge>
const data = inject('data') as Ref<DnsChallenge & Cert>
const keyType = shallowRef([
{
key: '2048',
name: 'RSA2048',
},
{
key: '3072',
name: 'RSA3072',
},
{
key: '4096',
name: 'RSA4096',
},
{
key: '8192',
name: 'RAS8192',
},
{
key: 'P256',
name: 'EC256',
},
{
key: 'P384',
name: 'EC384',
},
])
onMounted(() => {
if (data.value.key_type === '')
data.value.key_type = 'RSA2048'
})
</script>
<template>
@ -72,6 +105,17 @@ const data = inject('data') as Ref<DnsChallenge>
</ASelectOption>
</ASelect>
</AFormItem>
<AFormItem :label="$gettext('Key Type')">
<ASelect v-model:value="data.key_type">
<ASelectOption
v-for="t in keyType"
:key="t.key"
:value="t.key"
>
{{ t.name }}
</ASelectOption>
</ASelect>
</AFormItem>
</AForm>
<DNSChallenge v-if="data.challenge_method === 'dns01'" />
</div>

View file

@ -59,7 +59,7 @@ function log(msg: string) {
logContainer.value?.scroll({ top: 100000, left: 0, behavior: 'smooth' })
}
const issue_cert = async (config_name: string, server_name: string[]) => {
const issue_cert = async (config_name: string, server_name: string[], key_type: string) => {
return new Promise<CertificateResult>((resolve, reject) => {
progressStatus.value = 'active'
modalClosable.value = false
@ -74,6 +74,7 @@ const issue_cert = async (config_name: string, server_name: string[]) => {
ws.onopen = () => {
ws.send(JSON.stringify({
server_name,
key_type,
...data.value,
}))
}

View file

@ -74,6 +74,7 @@ func renew(certModel *model.Cert) {
ServerName: certModel.Domains,
ChallengeMethod: certModel.ChallengeMethod,
DNSCredentialID: certModel.DnsCredentialID,
KeyType: certModel.GetKeyType(),
}
// errChan will be closed inside IssueCert

View file

@ -32,9 +32,10 @@ const (
)
type ConfigPayload struct {
ServerName []string `json:"server_name"`
ChallengeMethod string `json:"challenge_method"`
DNSCredentialID int `json:"dns_credential_id"`
ServerName []string `json:"server_name"`
ChallengeMethod string `json:"challenge_method"`
DNSCredentialID int `json:"dns_credential_id"`
KeyType certcrypto.KeyType `json:"key_type"`
}
func IssueCert(payload *ConfigPayload, logChan chan string, errChan chan error) {
@ -93,7 +94,7 @@ func IssueCert(payload *ConfigPayload, logChan chan string, errChan chan error)
}
}
config.Certificate.KeyType = certcrypto.RSA2048
config.Certificate.KeyType = payload.KeyType
l.Println("[INFO] [Nginx UI] Creating client facilitates communication with the CA server")
// A client facilitates communication with the CA server.

View file

@ -0,0 +1,15 @@
package validation
import (
"github.com/go-acme/lego/v4/certcrypto"
val "github.com/go-playground/validator/v10"
)
func autoCertKeyType(fl val.FieldLevel) bool {
switch certcrypto.KeyType(fl.Field().String()) {
case certcrypto.RSA2048, certcrypto.RSA3072, certcrypto.RSA4096,
certcrypto.EC256, certcrypto.EC384:
return true
}
return false
}

View file

@ -42,5 +42,11 @@ func Init() {
logger.Fatal(err)
}
err = v.RegisterValidation("auto_cert_key_type", autoCertKeyType)
if err != nil {
logger.Fatal(err)
}
return
}

View file

@ -2,6 +2,7 @@ package model
import (
"github.com/0xJacky/Nginx-UI/internal/nginx"
"github.com/go-acme/lego/v4/certcrypto"
"github.com/lib/pq"
"os"
)
@ -17,16 +18,17 @@ type CertDomains []string
type Cert struct {
Model
Name string `json:"name"`
Domains pq.StringArray `json:"domains" gorm:"type:text[]"`
Filename string `json:"filename"`
SSLCertificatePath string `json:"ssl_certificate_path"`
SSLCertificateKeyPath string `json:"ssl_certificate_key_path"`
AutoCert int `json:"auto_cert"`
ChallengeMethod string `json:"challenge_method"`
DnsCredentialID int `json:"dns_credential_id"`
DnsCredential *DnsCredential `json:"dns_credential,omitempty"`
Log string `json:"log"`
Name string `json:"name"`
Domains pq.StringArray `json:"domains" gorm:"type:text[]"`
Filename string `json:"filename"`
SSLCertificatePath string `json:"ssl_certificate_path"`
SSLCertificateKeyPath string `json:"ssl_certificate_key_path"`
AutoCert int `json:"auto_cert"`
ChallengeMethod string `json:"challenge_method"`
DnsCredentialID int `json:"dns_credential_id"`
DnsCredential *DnsCredential `json:"dns_credential,omitempty"`
KeyType certcrypto.KeyType `json:"key_type"`
Log string `json:"log"`
}
func FirstCert(confName string) (c Cert, err error) {
@ -90,3 +92,12 @@ func (c *Cert) Remove() error {
return db.Where("filename", c.Filename).Delete(c).Error
}
func (c *Cert) GetKeyType() certcrypto.KeyType {
switch c.KeyType {
case certcrypto.RSA2048, certcrypto.RSA3072, certcrypto.RSA4096,
certcrypto.EC256, certcrypto.EC384:
return c.KeyType
}
return certcrypto.RSA2048
}