Browse Source

feat: add LogDirWhiteList option

Jacky 7 months ago
parent
commit
6d09ff5919

+ 1 - 0
.gitignore

@@ -11,3 +11,4 @@ nginx-ui
 resources/development/nginx
 resources/development/nginx
 app/.env
 app/.env
 app/.status_hash
 app/.status_hash
+casdoor.pub

+ 51 - 5
api/nginx/nginx_log.go

@@ -2,9 +2,13 @@ package nginx
 
 
 import (
 import (
 	"encoding/json"
 	"encoding/json"
+	"fmt"
 	"github.com/0xJacky/Nginx-UI/api"
 	"github.com/0xJacky/Nginx-UI/api"
+	"github.com/0xJacky/Nginx-UI/internal/cache"
+	"github.com/0xJacky/Nginx-UI/internal/helper"
 	"github.com/0xJacky/Nginx-UI/internal/logger"
 	"github.com/0xJacky/Nginx-UI/internal/logger"
 	"github.com/0xJacky/Nginx-UI/internal/nginx"
 	"github.com/0xJacky/Nginx-UI/internal/nginx"
+	"github.com/0xJacky/Nginx-UI/settings"
 	"github.com/gin-gonic/gin"
 	"github.com/gin-gonic/gin"
 	"github.com/gorilla/websocket"
 	"github.com/gorilla/websocket"
 	"github.com/hpcloud/tail"
 	"github.com/hpcloud/tail"
@@ -30,6 +34,7 @@ type controlStruct struct {
 type nginxLogPageResp struct {
 type nginxLogPageResp struct {
 	Content string `json:"content"`
 	Content string `json:"content"`
 	Page    int64  `json:"page"`
 	Page    int64  `json:"page"`
+	Error   string `json:"error,omitempty"`
 }
 }
 
 
 func GetNginxLogPage(c *gin.Context) {
 func GetNginxLogPage(c *gin.Context) {
@@ -46,6 +51,9 @@ func GetNginxLogPage(c *gin.Context) {
 	logPath, err := getLogPath(&control)
 	logPath, err := getLogPath(&control)
 
 
 	if err != nil {
 	if err != nil {
+		c.JSON(http.StatusInternalServerError, nginxLogPageResp{
+			Error: err.Error(),
+		})
 		logger.Error(err)
 		logger.Error(err)
 		return
 		return
 	}
 	}
@@ -53,13 +61,17 @@ func GetNginxLogPage(c *gin.Context) {
 	logFileStat, err := os.Stat(logPath)
 	logFileStat, err := os.Stat(logPath)
 
 
 	if err != nil {
 	if err != nil {
-		c.JSON(http.StatusOK, nginxLogPageResp{})
+		c.JSON(http.StatusInternalServerError, nginxLogPageResp{
+			Error: err.Error(),
+		})
 		logger.Error(err)
 		logger.Error(err)
 		return
 		return
 	}
 	}
 
 
 	if !logFileStat.Mode().IsRegular() {
 	if !logFileStat.Mode().IsRegular() {
-		c.JSON(http.StatusOK, nginxLogPageResp{})
+		c.JSON(http.StatusInternalServerError, nginxLogPageResp{
+			Error: "log file is not regular file",
+		})
 		logger.Error("log file is not regular file:", logPath)
 		logger.Error("log file is not regular file:", logPath)
 		return
 		return
 	}
 	}
@@ -67,7 +79,9 @@ func GetNginxLogPage(c *gin.Context) {
 	f, err := os.Open(logPath)
 	f, err := os.Open(logPath)
 
 
 	if err != nil {
 	if err != nil {
-		c.JSON(http.StatusOK, nginxLogPageResp{})
+		c.JSON(http.StatusInternalServerError, nginxLogPageResp{
+			Error: err.Error(),
+		})
 		logger.Error(err)
 		logger.Error(err)
 		return
 		return
 	}
 	}
@@ -90,7 +104,9 @@ func GetNginxLogPage(c *gin.Context) {
 	// seek
 	// seek
 	_, err = f.Seek(offset, io.SeekStart)
 	_, err = f.Seek(offset, io.SeekStart)
 	if err != nil && err != io.EOF {
 	if err != nil && err != io.EOF {
-		c.JSON(http.StatusOK, nginxLogPageResp{})
+		c.JSON(http.StatusInternalServerError, nginxLogPageResp{
+			Error: err.Error(),
+		})
 		logger.Error(err)
 		logger.Error(err)
 		return
 		return
 	}
 	}
@@ -98,7 +114,9 @@ func GetNginxLogPage(c *gin.Context) {
 	n, err := f.Read(buf)
 	n, err := f.Read(buf)
 
 
 	if err != nil && err != io.EOF {
 	if err != nil && err != io.EOF {
-		c.JSON(http.StatusOK, nginxLogPageResp{})
+		c.JSON(http.StatusInternalServerError, nginxLogPageResp{
+			Error: err.Error(),
+		})
 		logger.Error(err)
 		logger.Error(err)
 		return
 		return
 	}
 	}
@@ -109,7 +127,30 @@ func GetNginxLogPage(c *gin.Context) {
 	})
 	})
 }
 }
 
 
+// isLogPathUnderWhiteList checks if the log path is under one of the paths in LogDirWhiteList
+func isLogPathUnderWhiteList(path string) bool {
+	cacheKey := fmt.Sprintf("isLogPathUnderWhiteList:%s", path)
+	res, ok := cache.Get(cacheKey)
+	// no cache, check it
+	if !ok {
+		for _, whitePath := range settings.NginxSettings.LogDirWhiteList {
+			if helper.IsUnderDirectory(path, whitePath) {
+				cache.Set(cacheKey, true, 0)
+				return true
+			}
+		}
+		return false
+	}
+	return res.(bool)
+}
+
 func getLogPath(control *controlStruct) (logPath string, err error) {
 func getLogPath(control *controlStruct) (logPath string, err error) {
+	if len(settings.NginxSettings.LogDirWhiteList) == 0 {
+		err = errors.New("The settings.NginxSettings.LogDirWhiteList has not been configured. " +
+			"For security reasons, please configure a whitelist of log directories. " +
+			"Please visit https://nginxui.com/guide/config-nginx.html for more information.")
+		return
+	}
 	switch control.Type {
 	switch control.Type {
 	case "site":
 	case "site":
 		var config *nginx.NgxConfig
 		var config *nginx.NgxConfig
@@ -172,6 +213,11 @@ func getLogPath(control *controlStruct) (logPath string, err error) {
 		logPath = path
 		logPath = path
 	}
 	}
 
 
+	// check if logPath is under one of the paths in LogDirWhiteList
+	if !isLogPathUnderWhiteList(logPath) {
+		err = errors.New("The log path is not under the paths in LogDirWhiteList.")
+		return "", err
+	}
 	return
 	return
 }
 }
 
 

+ 4 - 2
app/src/views/nginx_log/NginxLog.vue

@@ -59,6 +59,9 @@ function init() {
   nginx_log.page(0, control).then(r => {
   nginx_log.page(0, control).then(r => {
     page.value = r.page - 1
     page.value = r.page - 1
     addLog(r.content)
     addLog(r.content)
+    openWs()
+  }).catch(e => {
+    addLog(e.error)
   })
   })
 }
 }
 
 
@@ -68,11 +71,10 @@ function clearLog() {
 
 
 onMounted(() => {
 onMounted(() => {
   init()
   init()
-  openWs()
 })
 })
 
 
 onUnmounted(() => {
 onUnmounted(() => {
-  websocket.close()
+  websocket?.close()
 })
 })
 
 
 watch(auto_refresh, value => {
 watch(auto_refresh, value => {

+ 29 - 0
casdoor.pub

@@ -0,0 +1,29 @@
+-----BEGIN CERTIFICATE-----
+MIIE3TCCAsWgAwIBAgIDAeJAMA0GCSqGSIb3DQEBCwUAMCgxDjAMBgNVBAoTBWFk
+bWluMRYwFAYDVQQDEw1jZXJ0LWJ1aWx0LWluMB4XDTI0MDcyOTAzMDUzM1oXDTQ0
+MDcyOTAzMDUzM1owKDEOMAwGA1UEChMFYWRtaW4xFjAUBgNVBAMTDWNlcnQtYnVp
+bHQtaW4wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDh0c2zvM21NDNi
+xZmSQVPOtckiH/K80mHQ99e+xzdGrZugaw00tyTOMVRot+Bv1cggcJXmFcVaa9Da
+siIcIQ6jT3w7mINsrErYu4nz9tELd4BZUM6tytN+khVqo73p/NbRsnmX8ykMyrgx
+YCBknNoSxh7glLSmKcj4uQ12dYakRPr0QNnDwU7fpPfB7N4O88yXWpbqWaABwqBx
+S6+tYUp9Wx74mH8c917w5xXx8EI5eC+dJOAeVXrbzqD7OdC+uo8m7f06HAX1vRE/
+MQS0BDx8tDGtqOvdJbVxdnS6MQ2E3vmuusFseDcKVgqTF/7b76y5uNyBBux5zfpt
+G1O3bquMlQ8mSedK8BBcbI79gXYJRWazMBXvAdacaV93dF1s0EEjYXiBManAci2d
+lH8zzs4TNpE0t3adYiPbGPW1F6Q+HaV52MDVpFwG9Ld0kJmKhkvoWiSXl58Db3VN
+Ef8Jjo2xF+5o9685CQ2o9L0RalcHxMxy1+6wdKMSp7PReYpIiEgmkAhUsKePOVmr
+JwL46/4EulcXrh+ASjobmknHzdBQEK+MHapb/XWewX4mzq777gPmP8RdILTHsc1m
+/hbR8uW9iTfo9LQFvXwnIPVfX0wzFXSZzSg/zLb2tN5D7VlDenUAdCDT1zNOfz5m
+9vLYwfo5GzXIkp2py0G40vrZlv7C9wIDAQABoxAwDjAMBgNVHRMBAf8EAjAAMA0G
+CSqGSIb3DQEBCwUAA4ICAQBp1Bx+mShpumQiVb2hv0amSzAKADyYIX3Xcef68rPu
+Eb+7HSCmQf4yyI9eU1TyvQCLbjum3U3OhDWwAiRvxOwj0oO/Q+dOUEZxTjbL9UF3
+4LIrUUBMRhRgy3wK73qy3o8hAcRtQyexUW7eoFS+7L++6XQOvMkYAtLO0DQCHeKG
+loiQa5RuWbzQDdP7810DLvNF8IMA8t9KKaKGybYze9WTzRUMTDbXby8pVs8DG7JI
+zIW6neEmtsVbxufk/nthG1b83/yZxe0StL42xI7f4xgguhkfd68E4lpf/gp91EAM
+K6MbTmCqkB68c0wOSXpWYkte7EvXTTmMSKf6FnMgOtqdxqYYMknLk4ZdI7tMqS31
+rpb9XxjBgXFbB18oOSDbW64KPMjE7vuOx+o32BTHKsUWxOiDc8+0ELrbhG2Bm1Gj
+CYkx9bq5iTLDwtZZlPoA8O/T0TJzBTtC/tlEdpHSkkLoEaWsx0nT9ipRWck1Kj59
+NGJkArbrpq9Ee8tWJKqTN/pv0X8r+MxowIY2dKvwweokXb7R6k9nfXyGw8ji22Hv
+H4iibv9FEyVFQ16HPR6fIKg9yE9u0223UhJZEwohA4DylCxpmI/YSXbUmzQJwjBP
+27qvT4Y07xsdNqIbkwhb5yEQB5huivITD+SBwI5NwDfUeY6eF/BEHpRq+Uy3itx0
+SA==
+-----END CERTIFICATE-----

+ 14 - 0
docs/guide/config-nginx.md

@@ -33,6 +33,20 @@ In Nginx UI v2, we parse the output of the `nginx -V` command to get the default
 If you need to set a different path, you can use this option.
 If you need to set a different path, you can use this option.
 :::
 :::
 
 
+### LogDirWhiteList
+
+- Type: `[]string`
+- Version:`>= v2.0.0-beta.36`
+- Example: `/var/log/nginx,/var/log/sites`
+
+This option is used to set the whitelist of directories for the Nginx logs viewer in Nginx UI.
+
+::: warning Warning
+For security reasons, you must specify the directories where the logs are stored. 
+
+Only logs within these directories can be viewed online.
+:::
+
 ## Service Monitoring and Control
 ## Service Monitoring and Control
 
 
 In this section, we will introduce configuration options in Nginx UI for monitoring and controlling Nginx services.
 In this section, we will introduce configuration options in Nginx UI for monitoring and controlling Nginx services.

+ 2 - 2
docs/package.json

@@ -7,11 +7,11 @@
     "docs:preview": "vitepress preview"
     "docs:preview": "vitepress preview"
   },
   },
   "dependencies": {
   "dependencies": {
-    "vitepress": "^1.3.4",
+    "vitepress": "^1.4.0",
     "vue": "^3.5.11"
     "vue": "^3.5.11"
   },
   },
   "devDependencies": {
   "devDependencies": {
-    "@types/node": "^22.7.4",
+    "@types/node": "^22.7.5",
     "less": "^4.2.0"
     "less": "^4.2.0"
   },
   },
   "license": "AGPL-3.0",
   "license": "AGPL-3.0",

+ 48 - 47
docs/pnpm-lock.yaml

@@ -9,15 +9,15 @@ importers:
   .:
   .:
     dependencies:
     dependencies:
       vitepress:
       vitepress:
-        specifier: ^1.3.4
-        version: 1.3.4(@algolia/client-search@4.24.0)(@types/node@22.7.4)(less@4.2.0)(postcss@8.4.47)(search-insights@2.13.0)
+        specifier: ^1.4.0
+        version: 1.4.0(@algolia/client-search@4.24.0)(@types/node@22.7.5)(less@4.2.0)(postcss@8.4.47)(search-insights@2.13.0)
       vue:
       vue:
         specifier: ^3.5.11
         specifier: ^3.5.11
         version: 3.5.11
         version: 3.5.11
     devDependencies:
     devDependencies:
       '@types/node':
       '@types/node':
-        specifier: ^22.7.4
-        version: 22.7.4
+        specifier: ^22.7.5
+        version: 22.7.5
       less:
       less:
         specifier: ^4.2.0
         specifier: ^4.2.0
         version: 4.2.0
         version: 4.2.0
@@ -350,20 +350,20 @@ packages:
     cpu: [x64]
     cpu: [x64]
     os: [win32]
     os: [win32]
 
 
-  '@shikijs/core@1.21.1':
-    resolution: {integrity: sha512-scBQo4V4O4WZLEDg11e75UPmXoCMq4Ya2A16U6efi/aTiR4o7T/GMNWZs2rq1U8dEvFKGxJZxiUy+tXgmr/4vw==}
+  '@shikijs/core@1.22.0':
+    resolution: {integrity: sha512-S8sMe4q71TJAW+qG93s5VaiihujRK6rqDFqBnxqvga/3LvqHEnxqBIOPkt//IdXVtHkQWKu4nOQNk0uBGicU7Q==}
 
 
-  '@shikijs/engine-javascript@1.21.1':
-    resolution: {integrity: sha512-29EG4KYKlAona8yikEx8uoKbK7N2YoXUO26LS1GOIxpMMIAlQS9UFONg95lkGmIfp1rRcvCvSpYYIJ/blsQxvg==}
+  '@shikijs/engine-javascript@1.22.0':
+    resolution: {integrity: sha512-AeEtF4Gcck2dwBqCFUKYfsCq0s+eEbCEbkUuFou53NZ0sTGnJnJ/05KHQFZxpii5HMXbocV9URYVowOP2wH5kw==}
 
 
-  '@shikijs/engine-oniguruma@1.21.1':
-    resolution: {integrity: sha512-PvfEtXCDbQZc9ud0SC0bPiuMbul44Cv0Ky2go4SsvVkYAAKYJsMe/Hx7nxThW8yS0r+w8USa0WfOtQKsD9DU9A==}
+  '@shikijs/engine-oniguruma@1.22.0':
+    resolution: {integrity: sha512-5iBVjhu/DYs1HB0BKsRRFipRrD7rqjxlWTj4F2Pf+nQSPqc3kcyqFFeZXnBMzDf0HdqaFVvhDRAGiYNvyLP+Mw==}
 
 
-  '@shikijs/transformers@1.21.1':
-    resolution: {integrity: sha512-97csTb0Gv8eLbglPDhNZTuAI9eCXOujNqD4qK6H0cjFNK+NBhkRIU02RgmYHZ7yNyLary6cEzY6WmUWb+al3MQ==}
+  '@shikijs/transformers@1.22.0':
+    resolution: {integrity: sha512-k7iMOYuGQA62KwAuJOQBgH2IQb5vP8uiB3lMvAMGUgAMMurePOx3Z7oNqJdcpxqZP6I9cc7nc4DNqSKduCxmdg==}
 
 
-  '@shikijs/types@1.21.1':
-    resolution: {integrity: sha512-yLuTJTCHmYznerJ0nxF+f2rBKHQf2FMAd08QL/3du2xNBy/7yQ8CjuKN4Zc+Pk0vfIFzdBoxdzvEXE4JtXoR4Q==}
+  '@shikijs/types@1.22.0':
+    resolution: {integrity: sha512-Fw/Nr7FGFhlQqHfxzZY8Cwtwk5E9nKDUgeLjZgt3UuhcM3yJR9xj3ZGNravZZok8XmEZMiYkSMTPlPkULB8nww==}
 
 
   '@shikijs/vscode-textmate@9.3.0':
   '@shikijs/vscode-textmate@9.3.0':
     resolution: {integrity: sha512-jn7/7ky30idSkd/O5yDBfAnVt+JJpepofP/POZ1iMOxK59cOfqIgg/Dj0eFsjOTMw+4ycJN0uhZH/Eb0bs/EUA==}
     resolution: {integrity: sha512-jn7/7ky30idSkd/O5yDBfAnVt+JJpepofP/POZ1iMOxK59cOfqIgg/Dj0eFsjOTMw+4ycJN0uhZH/Eb0bs/EUA==}
@@ -386,8 +386,8 @@ packages:
   '@types/mdurl@2.0.0':
   '@types/mdurl@2.0.0':
     resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==}
     resolution: {integrity: sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==}
 
 
-  '@types/node@22.7.4':
-    resolution: {integrity: sha512-y+NPi1rFzDs1NdQHHToqeiX2TIS79SWEAw9GYhkkx8bD0ChpfqC+n2j5OXOCpzfojBEBt6DnEnnG9MY0zk1XLg==}
+  '@types/node@22.7.5':
+    resolution: {integrity: sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==}
 
 
   '@types/unist@3.0.3':
   '@types/unist@3.0.3':
     resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
     resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==}
@@ -691,8 +691,8 @@ packages:
     resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==}
     resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==}
     hasBin: true
     hasBin: true
 
 
-  shiki@1.21.1:
-    resolution: {integrity: sha512-jSOKRHyQJxGOW3kJflmwzHJbp/kjg6hP8LYuVbCPw5oyX+fSNNoCywvcCD3w9eHbj2rvNljt7YMa5BP5Xi+nHg==}
+  shiki@1.22.0:
+    resolution: {integrity: sha512-/t5LlhNs+UOKQCYBtl5ZsH/Vclz73GIqT2yQsCBygr8L/ppTdmpL4w3kPLoZJbMKVWtoG77Ue1feOjZfDxvMkw==}
 
 
   source-map-js@1.2.1:
   source-map-js@1.2.1:
     resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
     resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
@@ -784,8 +784,8 @@ packages:
       terser:
       terser:
         optional: true
         optional: true
 
 
-  vitepress@1.3.4:
-    resolution: {integrity: sha512-I1/F6OW1xl3kW4PaIMC6snxjWgf3qfziq2aqsDoFc/Gt41WbcRv++z8zjw8qGRIJ+I4bUW7ZcKFDHHN/jkH9DQ==}
+  vitepress@1.4.0:
+    resolution: {integrity: sha512-JXCv4EsKTDyAFb6C/UjZr7nsGAzZ6mafVk2rx7rG5o8N+B/4QstIk+iEOe/9dKoU6V624UIC6g1pZ+K63rxhlw==}
     hasBin: true
     hasBin: true
     peerDependencies:
     peerDependencies:
       markdown-it-mathjax3: ^4
       markdown-it-mathjax3: ^4
@@ -1081,31 +1081,31 @@ snapshots:
   '@rollup/rollup-win32-x64-msvc@4.24.0':
   '@rollup/rollup-win32-x64-msvc@4.24.0':
     optional: true
     optional: true
 
 
-  '@shikijs/core@1.21.1':
+  '@shikijs/core@1.22.0':
     dependencies:
     dependencies:
-      '@shikijs/engine-javascript': 1.21.1
-      '@shikijs/engine-oniguruma': 1.21.1
-      '@shikijs/types': 1.21.1
+      '@shikijs/engine-javascript': 1.22.0
+      '@shikijs/engine-oniguruma': 1.22.0
+      '@shikijs/types': 1.22.0
       '@shikijs/vscode-textmate': 9.3.0
       '@shikijs/vscode-textmate': 9.3.0
       '@types/hast': 3.0.4
       '@types/hast': 3.0.4
       hast-util-to-html: 9.0.3
       hast-util-to-html: 9.0.3
 
 
-  '@shikijs/engine-javascript@1.21.1':
+  '@shikijs/engine-javascript@1.22.0':
     dependencies:
     dependencies:
-      '@shikijs/types': 1.21.1
+      '@shikijs/types': 1.22.0
       '@shikijs/vscode-textmate': 9.3.0
       '@shikijs/vscode-textmate': 9.3.0
       oniguruma-to-js: 0.4.3
       oniguruma-to-js: 0.4.3
 
 
-  '@shikijs/engine-oniguruma@1.21.1':
+  '@shikijs/engine-oniguruma@1.22.0':
     dependencies:
     dependencies:
-      '@shikijs/types': 1.21.1
+      '@shikijs/types': 1.22.0
       '@shikijs/vscode-textmate': 9.3.0
       '@shikijs/vscode-textmate': 9.3.0
 
 
-  '@shikijs/transformers@1.21.1':
+  '@shikijs/transformers@1.22.0':
     dependencies:
     dependencies:
-      shiki: 1.21.1
+      shiki: 1.22.0
 
 
-  '@shikijs/types@1.21.1':
+  '@shikijs/types@1.22.0':
     dependencies:
     dependencies:
       '@shikijs/vscode-textmate': 9.3.0
       '@shikijs/vscode-textmate': 9.3.0
       '@types/hast': 3.0.4
       '@types/hast': 3.0.4
@@ -1131,7 +1131,7 @@ snapshots:
 
 
   '@types/mdurl@2.0.0': {}
   '@types/mdurl@2.0.0': {}
 
 
-  '@types/node@22.7.4':
+  '@types/node@22.7.5':
     dependencies:
     dependencies:
       undici-types: 6.19.8
       undici-types: 6.19.8
 
 
@@ -1141,9 +1141,9 @@ snapshots:
 
 
   '@ungap/structured-clone@1.2.0': {}
   '@ungap/structured-clone@1.2.0': {}
 
 
-  '@vitejs/plugin-vue@5.1.4(vite@5.4.8(@types/node@22.7.4)(less@4.2.0))(vue@3.5.11)':
+  '@vitejs/plugin-vue@5.1.4(vite@5.4.8(@types/node@22.7.5)(less@4.2.0))(vue@3.5.11)':
     dependencies:
     dependencies:
-      vite: 5.4.8(@types/node@22.7.4)(less@4.2.0)
+      vite: 5.4.8(@types/node@22.7.5)(less@4.2.0)
       vue: 3.5.11
       vue: 3.5.11
 
 
   '@vue/compiler-core@3.5.11':
   '@vue/compiler-core@3.5.11':
@@ -1504,12 +1504,12 @@ snapshots:
   semver@5.7.2:
   semver@5.7.2:
     optional: true
     optional: true
 
 
-  shiki@1.21.1:
+  shiki@1.22.0:
     dependencies:
     dependencies:
-      '@shikijs/core': 1.21.1
-      '@shikijs/engine-javascript': 1.21.1
-      '@shikijs/engine-oniguruma': 1.21.1
-      '@shikijs/types': 1.21.1
+      '@shikijs/core': 1.22.0
+      '@shikijs/engine-javascript': 1.22.0
+      '@shikijs/engine-oniguruma': 1.22.0
+      '@shikijs/types': 1.22.0
       '@shikijs/vscode-textmate': 9.3.0
       '@shikijs/vscode-textmate': 9.3.0
       '@types/hast': 3.0.4
       '@types/hast': 3.0.4
 
 
@@ -1574,24 +1574,25 @@ snapshots:
       '@types/unist': 3.0.3
       '@types/unist': 3.0.3
       vfile-message: 4.0.2
       vfile-message: 4.0.2
 
 
-  vite@5.4.8(@types/node@22.7.4)(less@4.2.0):
+  vite@5.4.8(@types/node@22.7.5)(less@4.2.0):
     dependencies:
     dependencies:
       esbuild: 0.21.5
       esbuild: 0.21.5
       postcss: 8.4.47
       postcss: 8.4.47
       rollup: 4.24.0
       rollup: 4.24.0
     optionalDependencies:
     optionalDependencies:
-      '@types/node': 22.7.4
+      '@types/node': 22.7.5
       fsevents: 2.3.3
       fsevents: 2.3.3
       less: 4.2.0
       less: 4.2.0
 
 
-  vitepress@1.3.4(@algolia/client-search@4.24.0)(@types/node@22.7.4)(less@4.2.0)(postcss@8.4.47)(search-insights@2.13.0):
+  vitepress@1.4.0(@algolia/client-search@4.24.0)(@types/node@22.7.5)(less@4.2.0)(postcss@8.4.47)(search-insights@2.13.0):
     dependencies:
     dependencies:
       '@docsearch/css': 3.6.2
       '@docsearch/css': 3.6.2
       '@docsearch/js': 3.6.2(@algolia/client-search@4.24.0)(search-insights@2.13.0)
       '@docsearch/js': 3.6.2(@algolia/client-search@4.24.0)(search-insights@2.13.0)
-      '@shikijs/core': 1.21.1
-      '@shikijs/transformers': 1.21.1
+      '@shikijs/core': 1.22.0
+      '@shikijs/transformers': 1.22.0
+      '@shikijs/types': 1.22.0
       '@types/markdown-it': 14.1.2
       '@types/markdown-it': 14.1.2
-      '@vitejs/plugin-vue': 5.1.4(vite@5.4.8(@types/node@22.7.4)(less@4.2.0))(vue@3.5.11)
+      '@vitejs/plugin-vue': 5.1.4(vite@5.4.8(@types/node@22.7.5)(less@4.2.0))(vue@3.5.11)
       '@vue/devtools-api': 7.4.6
       '@vue/devtools-api': 7.4.6
       '@vue/shared': 3.5.11
       '@vue/shared': 3.5.11
       '@vueuse/core': 11.1.0(vue@3.5.11)
       '@vueuse/core': 11.1.0(vue@3.5.11)
@@ -1599,8 +1600,8 @@ snapshots:
       focus-trap: 7.6.0
       focus-trap: 7.6.0
       mark.js: 8.11.1
       mark.js: 8.11.1
       minisearch: 7.1.0
       minisearch: 7.1.0
-      shiki: 1.21.1
-      vite: 5.4.8(@types/node@22.7.4)(less@4.2.0)
+      shiki: 1.22.0
+      vite: 5.4.8(@types/node@22.7.5)(less@4.2.0)
       vue: 3.5.11
       vue: 3.5.11
     optionalDependencies:
     optionalDependencies:
       postcss: 8.4.47
       postcss: 8.4.47

+ 14 - 0
docs/zh_CN/guide/config-nginx.md

@@ -34,6 +34,20 @@ Nginx 日志对于监控、排查问题和维护您的 Web 服务器至关重要
 如果您需要设置不同的路径,您可以使用此选项。
 如果您需要设置不同的路径,您可以使用此选项。
 :::
 :::
 
 
+### LogDirWhiteList
+
+- 类型:`[]string`
+- 版本:`>= v2.0.0-beta.36`
+- 示例:`/var/log/nginx,/var/log/sites`
+
+此选项用于为 Nginx UI 设置日志查看器的目录白名单。
+
+::: warning 警告
+出于安全原因,您必须指定存储日志的目录。
+
+只有这些目录中的日志可以在线查看。
+:::
+
 ## 服务监控与控制
 ## 服务监控与控制
 
 
 在本节中,我们将会介绍 Nginx UI 中关于 Nginx 服务的监控和控制命令的配置选项。
 在本节中,我们将会介绍 Nginx UI 中关于 Nginx 服务的监控和控制命令的配置选项。

+ 14 - 0
docs/zh_TW/guide/config-nginx.md

@@ -33,6 +33,20 @@ Nginx 日誌對於監控、排查問題和維護您的 Web 伺服器至關重要
 如果您需要設置不同的路徑,您可以使用此選項。
 如果您需要設置不同的路徑,您可以使用此選項。
 :::
 :::
 
 
+### LogDirWhiteList
+
+- 類型:`[]string`
+- 版本:`>= v2.0.0-beta.36`
+- 示例:`/var/log/nginx,/var/log/sites`
+
+此選項用於為 Nginx UI 設置日誌查看器的目錄白名單。
+
+::: warning 警告
+出於安全原因,您必須指定存儲日誌的目錄。
+
+只有這些目錄中的日誌可以在線查看。
+:::
+
 ## 服務監控與控制
 ## 服務監控與控制
 
 
 在本節中,我們將會介紹 Nginx UI 中關於 Nginx 服務的監控和控制命令的配置選項。
 在本節中,我們將會介紹 Nginx UI 中關於 Nginx 服務的監控和控制命令的配置選項。

+ 8 - 7
settings/nginx.go

@@ -1,13 +1,14 @@
 package settings
 package settings
 
 
 type Nginx struct {
 type Nginx struct {
-	AccessLogPath string `json:"access_log_path" protected:"true"`
-	ErrorLogPath  string `json:"error_log_path" protected:"true"`
-	ConfigDir     string `json:"config_dir" protected:"true"`
-	PIDPath       string `json:"pid_path" protected:"true"`
-	TestConfigCmd string `json:"test_config_cmd" protected:"true"`
-	ReloadCmd     string `json:"reload_cmd" protected:"true"`
-	RestartCmd    string `json:"restart_cmd" protected:"true"`
+	AccessLogPath   string   `json:"access_log_path" protected:"true"`
+	ErrorLogPath    string   `json:"error_log_path" protected:"true"`
+	LogDirWhiteList []string `json:"log_dir_white_list" protected:"true"`
+	ConfigDir       string   `json:"config_dir" protected:"true"`
+	PIDPath         string   `json:"pid_path" protected:"true"`
+	TestConfigCmd   string   `json:"test_config_cmd" protected:"true"`
+	ReloadCmd       string   `json:"reload_cmd" protected:"true"`
+	RestartCmd      string   `json:"restart_cmd" protected:"true"`
 }
 }
 
 
 var NginxSettings = Nginx{
 var NginxSettings = Nginx{