Browse Source

audit fix

0xJacky 2 years ago
parent
commit
5fd3a57a69

+ 1 - 5
frontend/src/api/domain.ts

@@ -13,11 +13,7 @@ class Domain extends Curd {
     get_template() {
         return http.get('template')
     }
-
-    cert_info(path: string) {
-        return http.get('cert_info?ssl_certificate_path=' + path)
-    }
-
+    
     add_auto_cert(domain: string) {
         return http.post('cert/' + domain)
     }

+ 19 - 7
frontend/src/views/domain/DomainEdit.vue

@@ -24,6 +24,8 @@ const ngx_config = reactive({
     servers: []
 })
 
+const cert_info_map: any = reactive({})
+
 const auto_cert = ref(false)
 const enabled = ref(false)
 const configText = ref('')
@@ -33,13 +35,23 @@ const saving = ref(false)
 
 init()
 
+function handle_response(r: any) {
+
+    Object.keys(cert_info_map).forEach(v => {
+        delete cert_info_map[v]
+    })
+
+    configText.value = r.config
+    enabled.value = r.enabled
+    auto_cert.value = r.auto_cert
+    Object.assign(ngx_config, r.tokenized)
+    Object.assign(cert_info_map, r.cert_info)
+}
+
 function init() {
     if (name.value) {
         domain.get(name.value).then((r: any) => {
-            configText.value = r.config
-            enabled.value = r.enabled
-            auto_cert.value = r.auto_cert
-            Object.assign(ngx_config, r.tokenized)
+            handle_response(r)
         }).catch(r => {
             message.error(r.message ?? $gettext('Server error'))
         })
@@ -74,9 +86,8 @@ const save = async () => {
     }
 
     domain.save(name.value, {content: configText.value}).then(r => {
-        configText.value = r.config
-        enabled.value = r.enabled
-        Object.assign(ngx_config, r.tokenized)
+        handle_response(r)
+
         message.success($gettext('Saved successfully'))
 
     }).catch((e: any) => {
@@ -151,6 +162,7 @@ function on_change_enabled(checked: boolean) {
                     <ngx-config-editor
                         ref="ngx_config_editor"
                         :ngx_config="ngx_config"
+                        :cert_info="cert_info_map"
                         v-model:auto_cert="auto_cert"
                         :enabled="enabled"
                         @callback="save()"

+ 3 - 15
frontend/src/views/domain/cert/Cert.vue

@@ -3,19 +3,11 @@ import CertInfo from '@/views/domain/cert/CertInfo.vue'
 import IssueCert from '@/views/domain/cert/IssueCert.vue'
 import {computed, ref} from 'vue'
 
-const props = defineProps(['directivesMap', 'current_server_directives', 'enabled'])
+const props = defineProps(['directivesMap', 'current_server_directives', 'enabled', 'cert_info'])
 
 const emit = defineEmits(['callback', 'update:enabled'])
 
-const info = ref(null)
-
-interface Info {
-    get(): void
-}
-
 function callback() {
-    const t: Info | null = info.value
-    t!.get()
     emit('callback')
 }
 
@@ -23,11 +15,6 @@ const name = computed(() => {
     return props.directivesMap['server_name'][0].params.trim()
 })
 
-const ssl_certificate_path = computed(() => {
-    return props.directivesMap['ssl_certificate']?.[0].params.trim() ?? null
-})
-
-
 const enabled = computed({
     get() {
         return props.enabled
@@ -41,7 +28,8 @@ const enabled = computed({
 
 <template>
     <div>
-        <cert-info ref="info" :ssl_certificate_path="ssl_certificate_path" v-if="ssl_certificate_path"/>
+        <cert-info ref="info" :cert="props.cert_info"/>
+
         <issue-cert
             :current_server_directives="props.current_server_directives"
             :directives-map="props.directivesMap"

+ 3 - 19
frontend/src/views/domain/cert/CertInfo.vue

@@ -4,29 +4,13 @@ import dayjs from 'dayjs'
 import {reactive, ref} from 'vue'
 import domain from '@/api/domain'
 
-const props = defineProps(['ssl_certificate_path'])
+const props = defineProps(['cert'])
 
-const ok = ref(false)
-const cert = reactive({issuer_name: '', subject_name: '', not_after: '', not_before: ''})
-
-get()
-
-function get() {
-    domain.cert_info(props.ssl_certificate_path).then((r: any) => {
-        Object.assign(cert, r)
-        ok.value = true
-    }).catch(() => {
-        ok.value = false
-    })
-}
-
-defineExpose({
-    get
-})
+const cert = props.cert
 </script>
 
 <template>
-    <div class="cert-info" v-if="ok">
+    <div class="cert-info" v-if="cert">
         <h2 v-translate>Certificate Status</h2>
         <p v-translate="{issuer: cert.issuer_name}">Intermediate Certification Authorities: %{issuer}</p>
         <p v-translate="{name: cert.subject_name}">Subject Name: %{name}</p>

+ 2 - 1
frontend/src/views/domain/ngx_conf/NgxConfigEditor.vue

@@ -8,7 +8,7 @@ import Cert from '@/views/domain/cert/Cert.vue'
 
 const {$gettext} = useGettext()
 
-const props = defineProps(['ngx_config', 'auto_cert', 'enabled'])
+const props = defineProps(['ngx_config', 'auto_cert', 'enabled', 'cert_info'])
 
 const emit = defineEmits(['callback', 'update:auto_cert'])
 
@@ -143,6 +143,7 @@ const autoCertRef = computed({
                     <template v-if="current_support_ssl&&enabled">
                         <cert
                             v-if="current_support_ssl"
+                            :cert_info="props.cert_info[k]"
                             :current_server_directives="current_server_directives"
                             :directives-map="directivesMap"
                             v-model:enabled="autoCertRef"

+ 125 - 148
server/api/cert.go

@@ -1,155 +1,132 @@
 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"
-    "os"
+	"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"
+	"os"
 )
 
-func CertInfo(c *gin.Context) {
-    path := c.Query("ssl_certificate_path")
-
-    log.Println(path)
-
-    key, err := cert.GetCertInfo(path)
-
-    if err != nil {
-        c.JSON(http.StatusInternalServerError, gin.H{
-            "message": "Failed to get certificate information",
-            "error":   err.Error(),
-        })
-        return
-    }
-
-    c.JSON(http.StatusOK, gin.H{
-        "subject_name": key.Subject.CommonName,
-        "issuer_name":  key.Issuer.CommonName,
-        "not_after":    key.NotAfter,
-        "not_before":   key.NotBefore,
-    })
-}
-
 func IssueCert(c *gin.Context) {
-    domain := c.Param("domain")
-
-    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
-    }
-
-    defer func(ws *websocket.Conn) {
-        err := ws.Close()
-        if err != nil {
-            log.Println("defer websocket close err", err)
-        }
-    }(ws)
-
-    // read
-    mt, message, err := ws.ReadMessage()
-    if err != nil {
-        log.Println(err)
-        return
-    }
-
-    if mt == websocket.TextMessage && string(message) == "go" {
-
-        err = cert.IssueCert(domain)
-
-        if err != nil {
-
-            log.Println(err)
-
-            err = ws.WriteJSON(gin.H{
-                "status":  "error",
-                "message": err.Error(),
-            })
-
-            if err != nil {
-                log.Println(err)
-                return
-            }
-
-            return
-        }
-
-        sslCertificatePath := nginx.GetNginxConfPath("ssl/" + domain + "/fullchain.cer")
-        _, err = os.Stat(sslCertificatePath)
-
-        if err != nil {
-            log.Println(err)
-            return
-        }
-
-        log.Println("[found]", "fullchain.cer")
-
-        err = ws.WriteJSON(gin.H{
-            "status":  "success",
-            "message": "[found] fullchain.cer",
-        })
-
-        if err != nil {
-            log.Println(err)
-            return
-        }
-
-        sslCertificateKeyPath := nginx.GetNginxConfPath("ssl/" + domain + "/" + domain + ".key")
-        _, err = os.Stat(sslCertificateKeyPath)
-
-        if err != nil {
-            log.Println(err)
-            return
-        }
-
-        log.Println("[found]", "cert key")
-        err = ws.WriteJSON(gin.H{
-            "status":  "success",
-            "message": "[found] Certificate Key",
-        })
-
-        if err != nil {
-            log.Println(err)
-            return
-        }
-
-        certModel, err := model.FirstCert(domain)
-
-        if err != nil {
-            log.Println(err)
-            return
-        }
-
-        err = certModel.Updates(&model.Cert{
-            SSLCertificatePath: sslCertificatePath,
-        })
-
-        if err != nil {
-            log.Println(err)
-            return
-        }
-
-        err = ws.WriteJSON(gin.H{
-            "status":              "success",
-            "message":             "Issued certificate successfully",
-            "ssl_certificate":     sslCertificatePath,
-            "ssl_certificate_key": sslCertificateKeyPath,
-        })
-
-        if err != nil {
-            log.Println(err)
-            return
-        }
-    }
+	domain := c.Param("domain")
+
+	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
+	}
+
+	defer func(ws *websocket.Conn) {
+		err := ws.Close()
+		if err != nil {
+			log.Println("defer websocket close err", err)
+		}
+	}(ws)
+
+	// read
+	mt, message, err := ws.ReadMessage()
+	if err != nil {
+		log.Println(err)
+		return
+	}
+
+	if mt == websocket.TextMessage && string(message) == "go" {
+
+		err = cert.IssueCert(domain)
+
+		if err != nil {
+
+			log.Println(err)
+
+			err = ws.WriteJSON(gin.H{
+				"status":  "error",
+				"message": err.Error(),
+			})
+
+			if err != nil {
+				log.Println(err)
+				return
+			}
+
+			return
+		}
+
+		sslCertificatePath := nginx.GetNginxConfPath("ssl/" + domain + "/fullchain.cer")
+		_, err = os.Stat(sslCertificatePath)
+
+		if err != nil {
+			log.Println(err)
+			return
+		}
+
+		log.Println("[found]", "fullchain.cer")
+
+		err = ws.WriteJSON(gin.H{
+			"status":  "success",
+			"message": "[found] fullchain.cer",
+		})
+
+		if err != nil {
+			log.Println(err)
+			return
+		}
+
+		sslCertificateKeyPath := nginx.GetNginxConfPath("ssl/" + domain + "/" + domain + ".key")
+		_, err = os.Stat(sslCertificateKeyPath)
+
+		if err != nil {
+			log.Println(err)
+			return
+		}
+
+		log.Println("[found]", "cert key")
+		err = ws.WriteJSON(gin.H{
+			"status":  "success",
+			"message": "[found] Certificate Key",
+		})
+
+		if err != nil {
+			log.Println(err)
+			return
+		}
+
+		certModel, err := model.FirstCert(domain)
+
+		if err != nil {
+			log.Println(err)
+			return
+		}
+
+		err = certModel.Updates(&model.Cert{
+			SSLCertificatePath: sslCertificatePath,
+		})
+
+		if err != nil {
+			log.Println(err)
+			return
+		}
+
+		err = ws.WriteJSON(gin.H{
+			"status":              "success",
+			"message":             "Issued certificate successfully",
+			"ssl_certificate":     sslCertificatePath,
+			"ssl_certificate_key": sslCertificateKeyPath,
+		})
+
+		if err != nil {
+			log.Println(err)
+			return
+		}
+	}
 }

+ 53 - 18
server/api/domain.go

@@ -2,13 +2,16 @@ 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/config_list"
-	nginx2 "github.com/0xJacky/Nginx-UI/server/pkg/nginx"
+	"github.com/0xJacky/Nginx-UI/server/pkg/nginx"
 	"github.com/gin-gonic/gin"
+	"log"
 	"net/http"
 	"os"
 	"path/filepath"
 	"strings"
+	"time"
 )
 
 func GetDomains(c *gin.Context) {
@@ -21,14 +24,14 @@ func GetDomains(c *gin.Context) {
 		"modify":  "time",
 	}
 
-	configFiles, err := os.ReadDir(nginx2.GetNginxConfPath("sites-available"))
+	configFiles, err := os.ReadDir(nginx.GetNginxConfPath("sites-available"))
 
 	if err != nil {
 		ErrHandler(c, err)
 		return
 	}
 
-	enabledConfig, err := os.ReadDir(filepath.Join(nginx2.GetNginxConfPath("sites-enabled")))
+	enabledConfig, err := os.ReadDir(filepath.Join(nginx.GetNginxConfPath("sites-enabled")))
 
 	if err != nil {
 		ErrHandler(c, err)
@@ -62,22 +65,53 @@ func GetDomains(c *gin.Context) {
 	})
 }
 
+type CertificateInfo struct {
+	SubjectName string    `json:"subject_name"`
+	IssuerName  string    `json:"issuer_name"`
+	NotAfter    time.Time `json:"not_after"`
+	NotBefore   time.Time `json:"not_before"`
+}
+
 func GetDomain(c *gin.Context) {
 	name := c.Param("name")
-	path := filepath.Join(nginx2.GetNginxConfPath("sites-available"), name)
+	path := filepath.Join(nginx.GetNginxConfPath("sites-available"), name)
 
 	enabled := true
-	if _, err := os.Stat(filepath.Join(nginx2.GetNginxConfPath("sites-enabled"), name)); os.IsNotExist(err) {
+	if _, err := os.Stat(filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name)); os.IsNotExist(err) {
 		enabled = false
 	}
 
-	config, err := nginx2.ParseNgxConfig(path)
+	config, err := nginx.ParseNgxConfig(path)
 
 	if err != nil {
 		ErrHandler(c, err)
 		return
 	}
 
+	certInfoMap := make(map[int]CertificateInfo)
+	for serverIdx, server := range config.Servers {
+		for _, directive := range server.Directives {
+			if directive.Directive == "ssl_certificate" {
+
+				pubKey, err := cert.GetCertInfo(directive.Params)
+
+				if err != nil {
+					log.Println("Failed to get certificate information", err)
+					break
+				}
+
+				certInfoMap[serverIdx] = CertificateInfo{
+					SubjectName: pubKey.Subject.CommonName,
+					IssuerName:  pubKey.Issuer.CommonName,
+					NotAfter:    pubKey.NotAfter,
+					NotBefore:   pubKey.NotBefore,
+				}
+
+				break
+			}
+		}
+	}
+
 	_, err = model.FirstCert(name)
 
 	c.JSON(http.StatusOK, gin.H{
@@ -86,6 +120,7 @@ func GetDomain(c *gin.Context) {
 		"config":    config.BuildConfig(),
 		"tokenized": config,
 		"auto_cert": err == nil,
+		"cert_info": certInfoMap,
 	})
 
 }
@@ -95,7 +130,7 @@ func EditDomain(c *gin.Context) {
 	name := c.Param("name")
 	request := make(gin.H)
 	err = c.BindJSON(&request)
-	path := filepath.Join(nginx2.GetNginxConfPath("sites-available"), name)
+	path := filepath.Join(nginx.GetNginxConfPath("sites-available"), name)
 
 	err = os.WriteFile(path, []byte(request["content"].(string)), 0644)
 	if err != nil {
@@ -103,10 +138,10 @@ func EditDomain(c *gin.Context) {
 		return
 	}
 
-	enabledConfigFilePath := filepath.Join(nginx2.GetNginxConfPath("sites-enabled"), name)
+	enabledConfigFilePath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name)
 	if _, err = os.Stat(enabledConfigFilePath); err == nil {
 		// Test nginx configuration
-		err = nginx2.TestNginxConf()
+		err = nginx.TestNginxConf()
 		if err != nil {
 			c.JSON(http.StatusInternalServerError, gin.H{
 				"message": err.Error(),
@@ -114,7 +149,7 @@ func EditDomain(c *gin.Context) {
 			return
 		}
 
-		output := nginx2.ReloadNginx()
+		output := nginx.ReloadNginx()
 
 		if output != "" && strings.Contains(output, "error") {
 			c.JSON(http.StatusInternalServerError, gin.H{
@@ -128,8 +163,8 @@ func EditDomain(c *gin.Context) {
 }
 
 func EnableDomain(c *gin.Context) {
-	configFilePath := filepath.Join(nginx2.GetNginxConfPath("sites-available"), c.Param("name"))
-	enabledConfigFilePath := filepath.Join(nginx2.GetNginxConfPath("sites-enabled"), c.Param("name"))
+	configFilePath := filepath.Join(nginx.GetNginxConfPath("sites-available"), c.Param("name"))
+	enabledConfigFilePath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), c.Param("name"))
 
 	_, err := os.Stat(configFilePath)
 
@@ -148,7 +183,7 @@ func EnableDomain(c *gin.Context) {
 	}
 
 	// Test nginx config, if not pass then rollback.
-	err = nginx2.TestNginxConf()
+	err = nginx.TestNginxConf()
 	if err != nil {
 		_ = os.Remove(enabledConfigFilePath)
 		c.JSON(http.StatusInternalServerError, gin.H{
@@ -157,7 +192,7 @@ func EnableDomain(c *gin.Context) {
 		return
 	}
 
-	output := nginx2.ReloadNginx()
+	output := nginx.ReloadNginx()
 
 	if output != "" && strings.Contains(output, "error") {
 		c.JSON(http.StatusInternalServerError, gin.H{
@@ -172,7 +207,7 @@ func EnableDomain(c *gin.Context) {
 }
 
 func DisableDomain(c *gin.Context) {
-	enabledConfigFilePath := filepath.Join(nginx2.GetNginxConfPath("sites-enabled"), c.Param("name"))
+	enabledConfigFilePath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), c.Param("name"))
 
 	_, err := os.Stat(enabledConfigFilePath)
 
@@ -196,7 +231,7 @@ func DisableDomain(c *gin.Context) {
 		return
 	}
 
-	output := nginx2.ReloadNginx()
+	output := nginx.ReloadNginx()
 
 	if output != "" {
 		c.JSON(http.StatusInternalServerError, gin.H{
@@ -213,8 +248,8 @@ func DisableDomain(c *gin.Context) {
 func DeleteDomain(c *gin.Context) {
 	var err error
 	name := c.Param("name")
-	availablePath := filepath.Join(nginx2.GetNginxConfPath("sites-available"), name)
-	enabledPath := filepath.Join(nginx2.GetNginxConfPath("sites-enabled"), name)
+	availablePath := filepath.Join(nginx.GetNginxConfPath("sites-available"), name)
+	enabledPath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name)
 
 	if _, err = os.Stat(availablePath); os.IsNotExist(err) {
 		c.JSON(http.StatusNotFound, gin.H{

+ 7 - 8
server/router/routers.go

@@ -32,22 +32,22 @@ func InitRouter() *gin.Engine {
 		}
 	})
 
-	g := r.Group("/api")
+	root := r.Group("/api")
 	{
 
-		g.GET("settings", func(c *gin.Context) {
+		root.GET("settings", func(c *gin.Context) {
 			c.JSON(http.StatusOK, gin.H{
 				"demo": settings.ServerSettings.Demo,
 			})
 		})
 
-		g.GET("install", api.InstallLockCheck)
-		g.POST("install", api.InstallNginxUI)
+		root.GET("install", api.InstallLockCheck)
+		root.POST("install", api.InstallNginxUI)
 
-		g.POST("/login", api.Login)
-		g.DELETE("/logout", api.Logout)
+		root.POST("/login", api.Login)
+		root.DELETE("/logout", api.Logout)
 
-		g := g.Group("/", authRequired())
+		g := root.Group("/", authRequired())
 		{
 			g.GET("analytic", api.Analytic)
 			g.GET("analytic/init", api.GetAnalyticInit)
@@ -84,7 +84,6 @@ func InitRouter() *gin.Engine {
 			g.GET("template", api.GetTemplate)
 
 			g.GET("cert/issue/:domain", api.IssueCert)
-			g.GET("cert_info", api.CertInfo)
 
 			// Add domain to auto-renew cert list
 			g.POST("cert/:domain", api.AddDomainToAutoCert)