wip: support SAN certifications

This commit is contained in:
0xJacky 2022-12-20 18:07:07 +08:00
parent d7ce452b8b
commit 7d4999f83a
No known key found for this signature in database
GPG key ID: B6E4A6E4A561BAF0
5 changed files with 114 additions and 128 deletions

View file

@ -31,12 +31,6 @@ function job() {
return
}
if (server_name_more_than_one.value) {
message.error($gettext('server_name parameters more than one'))
issuing_cert.value = false
return
}
const server_name = props.directivesMap['server_name'][0]
if (!props.directivesMap['ssl_certificate']) {
@ -102,10 +96,12 @@ const issue_cert = async (server_name: string, callback: Function) => {
log($gettext('Getting the certificate, please wait...'))
const ws = websocket('/api/cert/issue/' + server_name, false)
const ws = websocket('/api/cert/issue', false)
ws.onopen = () => {
ws.send('go')
ws.send(JSON.stringify({
server_name: server_name.trim().split(' ')
}))
}
ws.onmessage = m => {
@ -132,11 +128,6 @@ const issue_cert = async (server_name: string, callback: Function) => {
}
}
const server_name_more_than_one = computed(() => {
return props.directivesMap['server_name'] && (props.directivesMap['server_name'].length > 1 ||
props.directivesMap['server_name'][0].params.trim().indexOf(' ') > 0)
})
const no_server_name = computed(() => {
return props.directivesMap['server_name'].length === 0
})
@ -154,11 +145,6 @@ const enabled = computed({
}
})
watch(server_name_more_than_one, () => {
emit('update:enabled', false)
onchange(false)
})
watch(no_server_name, () => {
emit('update:enabled', false)
onchange(false)
@ -166,7 +152,7 @@ watch(no_server_name, () => {
const progressStrokeColor = {
from: '#108ee9',
to: '#87d068',
to: '#87d068'
}
const progressPercent = ref(0)
@ -197,10 +183,10 @@ const modalClosable = ref(false)
:loading="issuing_cert"
v-model:checked="enabled"
@change="onchange"
:disabled="no_server_name||server_name_more_than_one"
:disabled="no_server_name"
/>
<a-alert
v-if="no_server_name||server_name_more_than_one"
v-if="no_server_name"
:message="$gettext('Warning')"
type="warning"
show-icon
@ -209,9 +195,6 @@ const modalClosable = ref(false)
<span v-if="no_server_name" v-translate>
server_name parameter is required
</span>
<span v-if="server_name_more_than_one" v-translate>
server_name parameters more than one
</span>
</template>
</a-alert>
</a-form-item>

View file

@ -1,140 +1,141 @@
package api
import (
"github.com/0xJacky/Nginx-UI/server/model"
"github.com/0xJacky/Nginx-UI/server/pkg/cert"
"github.com/0xJacky/Nginx-UI/server/pkg/nginx"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
"log"
"net/http"
"github.com/0xJacky/Nginx-UI/server/model"
"github.com/0xJacky/Nginx-UI/server/pkg/cert"
"github.com/0xJacky/Nginx-UI/server/pkg/nginx"
"github.com/gin-gonic/gin"
"github.com/gorilla/websocket"
"log"
"net/http"
"strings"
)
const (
Success = "success"
Info = "info"
Error = "error"
Success = "success"
Info = "info"
Error = "error"
)
type IssueCertResponse struct {
Status string `json:"status"`
Message string `json:"message"`
SSLCertificate string `json:"ssl_certificate,omitempty"`
SSLCertificateKey string `json:"ssl_certificate_key,omitempty"`
Status string `json:"status"`
Message string `json:"message"`
SSLCertificate string `json:"ssl_certificate,omitempty"`
SSLCertificateKey string `json:"ssl_certificate_key,omitempty"`
}
func handleIssueCertLogChan(conn *websocket.Conn, logChan chan string) {
defer func() {
if err := recover(); err != nil {
log.Println("api.handleIssueCertLogChan recover", err)
}
}()
defer func() {
if err := recover(); err != nil {
log.Println("api.handleIssueCertLogChan recover", err)
}
}()
for logString := range logChan {
for logString := range logChan {
err := conn.WriteJSON(IssueCertResponse{
Status: Info,
Message: logString,
})
err := conn.WriteJSON(IssueCertResponse{
Status: Info,
Message: logString,
})
if err != nil {
log.Println("Error handleIssueCertLogChan", err)
return
}
if err != nil {
log.Println("Error handleIssueCertLogChan", err)
return
}
}
}
}
func IssueCert(c *gin.Context) {
domain := c.Param("domain")
var upGrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true
},
}
var upGrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true
},
}
// upgrade http to websocket
ws, err := upGrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
log.Println(err)
return
}
// upgrade http to websocket
ws, err := upGrader.Upgrade(c.Writer, c.Request, nil)
if err != nil {
log.Println(err)
return
}
defer func(ws *websocket.Conn) {
err := ws.Close()
if err != nil {
log.Println("defer websocket close err", err)
}
}(ws)
defer func(ws *websocket.Conn) {
err := ws.Close()
if err != nil {
log.Println("defer websocket close err", err)
}
}(ws)
// read
var buffer struct {
ServerName []string `json:"server_name"`
}
// read
mt, message, err := ws.ReadMessage()
err = ws.ReadJSON(&buffer)
if err != nil {
log.Println(err)
return
}
if err != nil {
log.Println(err)
return
}
if mt != websocket.TextMessage || string(message) != "go" {
return
}
logChan := make(chan string, 1)
errChan := make(chan error, 1)
logChan := make(chan string, 1)
errChan := make(chan error, 1)
go cert.IssueCert(buffer.ServerName, logChan, errChan)
go cert.IssueCert(domain, logChan, errChan)
domain := strings.Join(buffer.ServerName, "_")
go handleIssueCertLogChan(ws, logChan)
go handleIssueCertLogChan(ws, logChan)
// block, unless errChan closed
for err = range errChan {
log.Println("Error cert.IssueCert", err)
// block, unless errChan closed
for err = range errChan {
log.Println("Error cert.IssueCert", err)
err = ws.WriteJSON(IssueCertResponse{
Status: Error,
Message: err.Error(),
})
err = ws.WriteJSON(IssueCertResponse{
Status: Error,
Message: err.Error(),
})
if err != nil {
log.Println(err)
return
}
if err != nil {
log.Println(err)
return
}
return
}
return
}
close(logChan)
close(logChan)
sslCertificatePath := nginx.GetNginxConfPath("ssl/" + domain + "/fullchain.cer")
sslCertificateKeyPath := nginx.GetNginxConfPath("ssl/" + domain + "/" + domain + ".key")
sslCertificatePath := nginx.GetNginxConfPath("ssl/" + domain + "/fullchain.cer")
sslCertificateKeyPath := nginx.GetNginxConfPath("ssl/" + domain + "/" + domain + ".key")
certModel, err := model.FirstCert(domain)
certModel, err := model.FirstCert(domain)
if err != nil {
log.Println(err)
return
}
if err != nil {
log.Println(err)
return
}
err = certModel.Updates(&model.Cert{
SSLCertificatePath: sslCertificatePath,
})
err = certModel.Updates(&model.Cert{
SSLCertificatePath: sslCertificatePath,
})
if err != nil {
log.Println(err)
return
}
if err != nil {
log.Println(err)
return
}
err = ws.WriteJSON(IssueCertResponse{
Status: Success,
Message: "Issued certificate successfully",
SSLCertificate: sslCertificatePath,
SSLCertificateKey: sslCertificateKeyPath,
})
err = ws.WriteJSON(IssueCertResponse{
Status: Success,
Message: "Issued certificate successfully",
SSLCertificate: sslCertificatePath,
SSLCertificateKey: sslCertificateKeyPath,
})
if err != nil {
log.Println(err)
return
}
if err != nil {
log.Println(err)
return
}
}

View file

@ -56,7 +56,7 @@ func AutoCert() {
logChan := make(chan string, 1)
errChan := make(chan error, 1)
go IssueCert(domain, logChan, errChan)
go IssueCert([]string{domain}, logChan, errChan)
go handleIssueCertLogChan(logChan)

View file

@ -16,6 +16,7 @@ import (
"log"
"os"
"path/filepath"
"strings"
)
// MyUser You'll need a user or account type that implements acme.User
@ -35,7 +36,7 @@ func (u *MyUser) GetPrivateKey() crypto.PrivateKey {
return u.key
}
func IssueCert(domain string, logChan chan string, errChan chan error) {
func IssueCert(domain []string, logChan chan string, errChan chan error) {
defer func() {
if err := recover(); err != nil {
log.Println("Issue Cert recover", err)
@ -94,7 +95,7 @@ func IssueCert(domain string, logChan chan string, errChan chan error) {
myUser.Registration = reg
request := certificate.ObtainRequest{
Domains: []string{domain},
Domains: domain,
Bundle: true,
}
@ -104,7 +105,8 @@ func IssueCert(domain string, logChan chan string, errChan chan error) {
errChan <- errors.Wrap(err, "issue cert fail to obtain")
return
}
saveDir := nginx.GetNginxConfPath("ssl/" + domain)
name := strings.Join(domain, "_")
saveDir := nginx.GetNginxConfPath("ssl/" + name)
if _, err = os.Stat(saveDir); os.IsNotExist(err) {
err = os.MkdirAll(saveDir, 0755)
if err != nil {
@ -125,7 +127,7 @@ func IssueCert(domain string, logChan chan string, errChan chan error) {
}
logChan <- "Writing certificate private key to disk"
err = os.WriteFile(filepath.Join(saveDir, domain+".key"),
err = os.WriteFile(filepath.Join(saveDir, name+".key"),
certificates.PrivateKey, 0644)
if err != nil {

View file

@ -83,7 +83,7 @@ func InitRouter() *gin.Engine {
g.GET("template", api.GetTemplate)
g.GET("cert/issue/:domain", api.IssueCert)
g.GET("cert/issue", api.IssueCert)
// Add domain to auto-renew cert list
g.POST("cert/:domain", api.AddDomainToAutoCert)