mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2025-05-11 02:15:48 +02:00
feat: configurable cert key type #264
This commit is contained in:
parent
a095c88fd2
commit
22d62e420b
12 changed files with 115 additions and 28 deletions
|
@ -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,
|
||||
})
|
||||
|
||||
|
|
|
@ -122,6 +122,7 @@ func IssueCert(c *gin.Context) {
|
|||
SSLCertificatePath: sslCertificatePath,
|
||||
SSLCertificateKeyPath: sslCertificateKeyPath,
|
||||
AutoCert: model.AutoCertEnabled,
|
||||
KeyType: payload.KeyType,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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')
|
||||
})
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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,
|
||||
}))
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
15
internal/validation/key_type.go
Normal file
15
internal/validation/key_type.go
Normal 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
|
||||
}
|
|
@ -42,5 +42,11 @@ func Init() {
|
|||
logger.Fatal(err)
|
||||
}
|
||||
|
||||
err = v.RegisterValidation("auto_cert_key_type", autoCertKeyType)
|
||||
|
||||
if err != nil {
|
||||
logger.Fatal(err)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue