Compare commits

..

3 commits

Author SHA1 Message Date
Nebulosa
25f64738e4
refactor: set header only if it not empty (#3763)
Some checks failed
Release 3X-UI / build (386) (push) Has been cancelled
Release 3X-UI / build (amd64) (push) Has been cancelled
Release 3X-UI / build (arm64) (push) Has been cancelled
Release 3X-UI / build (armv5) (push) Has been cancelled
Release 3X-UI / build (armv6) (push) Has been cancelled
Release 3X-UI / build (armv7) (push) Has been cancelled
Release 3X-UI / build (s390x) (push) Has been cancelled
Release 3X-UI / Build for Windows (push) Has been cancelled
2026-02-07 23:01:05 +01:00
Sanaei
5bb87fd3d4
fix : Uncontrolled data used in path expression
Co-Authored-By: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2026-02-07 22:54:40 +01:00
Mojtaba Arezoomand
491e3f9f8b
feat: add openssl to dockerfile (#3762) 2026-02-07 22:30:03 +01:00
4 changed files with 43 additions and 55 deletions

View file

@ -30,7 +30,8 @@ RUN apk add --no-cache --update \
tzdata \ tzdata \
fail2ban \ fail2ban \
bash \ bash \
curl curl \
openssl
COPY --from=builder /app/build/ /app/ COPY --from=builder /app/build/ /app/
COPY --from=builder /app/DockerEntrypoint.sh /app/ COPY --from=builder /app/DockerEntrypoint.sh /app/

View file

@ -182,10 +182,24 @@ func (a *SUBController) ApplyCommonHeaders(
) { ) {
c.Writer.Header().Set("Subscription-Userinfo", header) c.Writer.Header().Set("Subscription-Userinfo", header)
c.Writer.Header().Set("Profile-Update-Interval", updateInterval) c.Writer.Header().Set("Profile-Update-Interval", updateInterval)
c.Writer.Header().Set("Profile-Title", "base64:"+base64.StdEncoding.EncodeToString([]byte(profileTitle)))
c.Writer.Header().Set("Support-Url", profileSupportUrl) //Basics
c.Writer.Header().Set("Profile-Web-Page-Url", profileUrl) if profileTitle != "" {
c.Writer.Header().Set("Announce", "base64:"+base64.StdEncoding.EncodeToString([]byte(profileAnnounce))) c.Writer.Header().Set("Profile-Title", "base64:"+base64.StdEncoding.EncodeToString([]byte(profileTitle)))
}
if profileSupportUrl != "" {
c.Writer.Header().Set("Support-Url", profileSupportUrl)
}
if profileUrl != "" {
c.Writer.Header().Set("Profile-Web-Page-Url", profileUrl)
}
if profileAnnounce != "" {
c.Writer.Header().Set("Announce", "base64:"+base64.StdEncoding.EncodeToString([]byte(profileAnnounce)))
}
//Advanced (Happ)
c.Writer.Header().Set("Routing-Enable", strconv.FormatBool(profileEnableRouting)) c.Writer.Header().Set("Routing-Enable", strconv.FormatBool(profileEnableRouting))
c.Writer.Header().Set("Routing", profileRoutingRules) if profileRoutingRules != "" {
c.Writer.Header().Set("Routing", profileRoutingRules)
}
} }

View file

@ -3,7 +3,6 @@ package job
import ( import (
"bufio" "bufio"
"encoding/json" "encoding/json"
"fmt"
"io" "io"
"log" "log"
"os" "os"
@ -388,7 +387,7 @@ func (j *CheckClientIpJob) updateInboundClientIps(inboundClientIps *model.Inboun
// disconnectClientTemporarily removes and re-adds a client to force disconnect old connections // disconnectClientTemporarily removes and re-adds a client to force disconnect old connections
func (j *CheckClientIpJob) disconnectClientTemporarily(inbound *model.Inbound, clientEmail string, clients []model.Client) { func (j *CheckClientIpJob) disconnectClientTemporarily(inbound *model.Inbound, clientEmail string, clients []model.Client) {
var xrayAPI xray.XrayAPI var xrayAPI xray.XrayAPI
// Get panel settings for API port // Get panel settings for API port
db := database.GetDB() db := database.GetDB()
var apiPort int 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 { if err := db.Where("key = ?", "xrayApiPort").First(&apiPortSetting).Error; err == nil {
apiPort, _ = strconv.Atoi(apiPortSetting.Value) apiPort, _ = strconv.Atoi(apiPortSetting.Value)
} }
if apiPort == 0 { if apiPort == 0 {
apiPort = 10085 // Default API port apiPort = 10085 // Default API port
} }

View file

@ -1056,35 +1056,23 @@ func (s *ServerService) IsValidGeofileName(filename string) bool {
} }
func (s *ServerService) UpdateGeofile(fileName string) error { func (s *ServerService) UpdateGeofile(fileName string) error {
files := []struct { type geofileEntry struct {
URL string URL string
FileName string FileName string
}{ }
{"https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat", "geoip.dat"}, geofileAllowlist := map[string]geofileEntry{
{"https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geosite.dat", "geosite.dat"}, "geoip.dat": {"https://github.com/Loyalsoldier/v2ray-rules-dat/releases/latest/download/geoip.dat", "geoip.dat"},
{"https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geoip.dat", "geoip_IR.dat"}, "geosite.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/geosite.dat", "geosite_IR.dat"}, "geoip_IR.dat": {"https://github.com/chocolate4u/Iran-v2ray-rules/releases/latest/download/geoip.dat", "geoip_IR.dat"},
{"https://github.com/runetfreedom/russia-v2ray-rules-dat/releases/latest/download/geoip.dat", "geoip_RU.dat"}, "geosite_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/geosite.dat", "geosite_RU.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 // Strict allowlist check to avoid writing uncontrolled files
if fileName != "" { if fileName != "" {
// Use the centralized validation function if _, ok := geofileAllowlist[fileName]; !ok {
if !s.IsValidGeofileName(fileName) { return common.NewErrorf("Invalid geofile name: %q not in allowlist", 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)
} }
} }
@ -1159,32 +1147,18 @@ func (s *ServerService) UpdateGeofile(fileName string) error {
var errorMessages []string var errorMessages []string
if fileName == "" { if fileName == "" {
for _, file := range files { // Download all geofiles
// Sanitize the filename from our allowlist as an extra precaution for _, entry := range geofileAllowlist {
destPath := filepath.Join(config.GetBinFolderPath(), filepath.Base(file.FileName)) destPath := filepath.Join(config.GetBinFolderPath(), entry.FileName)
if err := downloadFile(file.URL, destPath); err != nil { if err := downloadFile(entry.URL, destPath); err != nil {
errorMessages = append(errorMessages, fmt.Sprintf("Error downloading Geofile '%s': %v", file.FileName, err)) errorMessages = append(errorMessages, fmt.Sprintf("Error downloading Geofile '%s': %v", entry.FileName, err))
} }
} }
} else { } else {
// Use filepath.Base to ensure we only get the filename component, no path traversal entry := geofileAllowlist[fileName]
safeName := filepath.Base(fileName) destPath := filepath.Join(config.GetBinFolderPath(), entry.FileName)
destPath := filepath.Join(config.GetBinFolderPath(), safeName) if err := downloadFile(entry.URL, destPath); err != nil {
errorMessages = append(errorMessages, fmt.Sprintf("Error downloading Geofile '%s': %v", entry.FileName, err))
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))
}
} }
} }