Files
nginx-ui/internal/nginx_log/utils/valid_path.go

101 lines
2.6 KiB
Go

package utils
import (
"fmt"
"os"
"path/filepath"
"github.com/0xJacky/Nginx-UI/internal/cache"
"github.com/0xJacky/Nginx-UI/internal/helper"
"github.com/0xJacky/Nginx-UI/internal/nginx"
"github.com/0xJacky/Nginx-UI/settings"
)
// IsValidLogPath checks if a log path is valid:
// 1. It must be a regular file or a symlink to a regular file
// 2. It must not point to a console or special device
// 3. It must be under the whitelist directories
func IsValidLogPath(logPath string) bool {
// First check if the path is in the whitelist
if !isLogPathUnderWhiteList(logPath) {
return false
}
// Check if the path exists
fileInfo, err := os.Lstat(logPath)
if err != nil {
// If the file doesn't exist, it might be created later
// We'll assume it's valid for now
return true
}
// If it's a symlink, follow it safely
if fileInfo.Mode()&os.ModeSymlink != 0 {
// Use EvalSymlinks to safely resolve the entire symlink chain
// This function detects circular symlinks and returns an error
resolvedPath, err := filepath.EvalSymlinks(logPath)
if err != nil {
return false
}
if !isLogPathUnderWhiteList(resolvedPath) {
return false
}
// Check the resolved target file
targetInfo, err := os.Stat(resolvedPath)
if err != nil {
return false
}
// Only accept regular files as targets
result := targetInfo.Mode().IsRegular()
return result
}
// For non-symlinks, just check if it's a regular file
result := fileInfo.Mode().IsRegular()
return result
}
// isLogPathUnderWhiteList checks if a log path is under one of the paths in LogDirWhiteList
func isLogPathUnderWhiteList(path string) bool {
prefix := nginx.GetPrefix()
cacheKey := fmt.Sprintf("isLogPathUnderWhiteList:%s", path)
res, ok := cache.Get(cacheKey)
// If cached, return the result directly
if ok {
return res.(bool)
}
// Only build the whitelist when cache miss occurs
logDirWhiteList := append([]string{}, settings.NginxSettings.LogDirWhiteList...)
accessLogPath := nginx.GetAccessLogPath()
errorLogPath := nginx.GetErrorLogPath()
if accessLogPath != "" {
logDirWhiteList = append(logDirWhiteList, filepath.Dir(accessLogPath))
}
if errorLogPath != "" {
logDirWhiteList = append(logDirWhiteList, filepath.Dir(errorLogPath))
}
if prefix != "" {
logDirWhiteList = append(logDirWhiteList, prefix)
}
// Check if path is under any whitelist directory
for _, whitePath := range logDirWhiteList {
if helper.IsUnderDirectory(path, whitePath) {
cache.Set(cacheKey, true, 0)
return true
}
}
// Cache negative result as well to avoid repeated checks
cache.Set(cacheKey, false, 0)
return false
}