diff options
| author | Sanaei <ho3ein.sanaei@gmail.com> | 2026-02-08 00:34:06 +0300 |
|---|---|---|
| committer | MHSanaei <ho3ein.sanaei@gmail.com> | 2026-02-08 00:54:40 +0300 |
| commit | 5bb87fd3d4142d606c3875641d7ca68aa8f1a5c4 (patch) | |
| tree | ca4a899e54f103a4042ba5d742a5bb872a86afca /web | |
| parent | 491e3f9f8bd70a35de489d6da1d10b8bac3a0851 (diff) | |
fix : Uncontrolled data used in path expression
Co-Authored-By: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Diffstat (limited to 'web')
| -rw-r--r-- | web/job/check_client_ip_job.go | 5 | ||||
| -rw-r--r-- | web/service/server.go | 66 |
2 files changed, 22 insertions, 49 deletions
diff --git a/web/job/check_client_ip_job.go b/web/job/check_client_ip_job.go index 94486236..d3c1a1d1 100644 --- a/web/job/check_client_ip_job.go +++ b/web/job/check_client_ip_job.go @@ -3,7 +3,6 @@ package job import ( "bufio" "encoding/json" - "fmt" "io" "log" "os" @@ -388,7 +387,7 @@ func (j *CheckClientIpJob) updateInboundClientIps(inboundClientIps *model.Inboun // disconnectClientTemporarily removes and re-adds a client to force disconnect old connections func (j *CheckClientIpJob) disconnectClientTemporarily(inbound *model.Inbound, clientEmail string, clients []model.Client) { var xrayAPI xray.XrayAPI - + // Get panel settings for API port db := database.GetDB() var apiPort int @@ -396,7 +395,7 @@ func (j *CheckClientIpJob) disconnectClientTemporarily(inbound *model.Inbound, c if err := db.Where("key = ?", "xrayApiPort").First(&apiPortSetting).Error; err == nil { apiPort, _ = strconv.Atoi(apiPortSetting.Value) } - + if apiPort == 0 { apiPort = 10085 // Default API port } diff --git a/web/service/server.go b/web/service/server.go index ec217e29..c78f7374 100644 --- a/web/service/server.go +++ b/web/service/server.go @@ -1056,35 +1056,23 @@ func (s *ServerService) IsValidGeofileName(filename string) bool { } func (s *ServerService) UpdateGeofile(fileName string) error { - files := []struct { + type geofileEntry struct { URL string FileName string - }{ - {"https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat", "geoip.dat"}, - {"https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat", "geosite.dat"}, - {"https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geoip.dat", "geoip_IR.dat"}, - {"https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geosite.dat", "geosite_IR.dat"}, - {"https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geoip.dat", "geoip_RU.dat"}, - {"https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geosite.dat", "geosite_RU.dat"}, + } + geofileAllowlist := map[string]geofileEntry{ + "geoip.dat": {"https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat", "geoip.dat"}, + "geosite.dat": {"https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat", "geosite.dat"}, + "geoip_IR.dat": {"https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geoip.dat", "geoip_IR.dat"}, + "geosite_IR.dat": {"https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geosite.dat", "geosite_IR.dat"}, + "geoip_RU.dat": {"https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geoip.dat", "geoip_RU.dat"}, + "geosite_RU.dat": {"https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geosite.dat", "geosite_RU.dat"}, } // Strict allowlist check to avoid writing uncontrolled files if fileName != "" { - // Use the centralized validation function - if !s.IsValidGeofileName(fileName) { - return common.NewErrorf("Invalid geofile name: contains unsafe path characters: %s", fileName) - } - - // Ensure the filename matches exactly one from our allowlist - isAllowed := false - for _, file := range files { - if fileName == file.FileName { - isAllowed = true - break - } - } - if !isAllowed { - return common.NewErrorf("Invalid geofile name: %s not in allowlist", fileName) + if _, ok := geofileAllowlist[fileName]; !ok { + return common.NewErrorf("Invalid geofile name: %q not in allowlist", fileName) } } @@ -1159,32 +1147,18 @@ func (s *ServerService) UpdateGeofile(fileName string) error { var errorMessages []string if fileName == "" { - for _, file := range files { - // Sanitize the filename from our allowlist as an extra precaution - destPath := filepath.Join(config.GetBinFolderPath(), filepath.Base(file.FileName)) - if err := downloadFile(file.URL, destPath); err != nil { - errorMessages = append(errorMessages, fmt.Sprintf("Error downloading Geofile '%s': %v", file.FileName, err)) + // Download all geofiles + for _, entry := range geofileAllowlist { + destPath := filepath.Join(config.GetBinFolderPath(), entry.FileName) + if err := downloadFile(entry.URL, destPath); err != nil { + errorMessages = append(errorMessages, fmt.Sprintf("Error downloading Geofile '%s': %v", entry.FileName, err)) } } } else { - // Use filepath.Base to ensure we only get the filename component, no path traversal - safeName := filepath.Base(fileName) - destPath := filepath.Join(config.GetBinFolderPath(), safeName) - - var fileURL string - for _, file := range files { - if file.FileName == fileName { - fileURL = file.URL - break - } - } - - if fileURL == "" { - errorMessages = append(errorMessages, fmt.Sprintf("File '%s' not found in the list of Geofiles", fileName)) - } else { - if err := downloadFile(fileURL, destPath); err != nil { - errorMessages = append(errorMessages, fmt.Sprintf("Error downloading Geofile '%s': %v", fileName, err)) - } + entry := geofileAllowlist[fileName] + destPath := filepath.Join(config.GetBinFolderPath(), entry.FileName) + if err := downloadFile(entry.URL, destPath); err != nil { + errorMessages = append(errorMessages, fmt.Sprintf("Error downloading Geofile '%s': %v", entry.FileName, err)) } } |
