diff --git a/common/lua/program_test.go b/common/lua/program_test.go index fbd34de19..1341e0d94 100644 --- a/common/lua/program_test.go +++ b/common/lua/program_test.go @@ -188,17 +188,9 @@ func TestCompileInlineDiagnostics(t *testing.T) { func TestCompileFileExtension(t *testing.T) { for _, name := range []string{"script", "script.dat", "script.lua.txt", "script.LUA"} { - path := filepath.Join(t.TempDir(), name) - if err := os.WriteFile(path, []byte("value = 42"), 0o600); err != nil { - t.Fatal(err) + if program, err := Compile(name); program != nil || err == nil || !strings.Contains(err.Error(), "Lua file extension must be .lua") { + t.Fatalf("Compile(%q) = %v, %v; want nil program and .lua extension error", name, program, err) } - if program, err := Compile(path); program != nil || err == nil || !strings.Contains(err.Error(), "Lua file extension must be .lua") { - t.Fatalf("Compile(%q) = %v, %v; want nil program and .lua extension error", path, program, err) - } - } - path := writeTestScript(t, "value = 42") + string(filepath.Separator) + "." - if program, err := Compile(path); program == nil || err != nil { - t.Fatalf("Compile(%q) = %v, %v; want acceptance of the resolved .lua path", path, program, err) } } @@ -234,10 +226,6 @@ func writeTestScript(t *testing.T, code string) string { if err := os.WriteFile(path, []byte(code), 0o600); err != nil { t.Fatal(err) } - path, err := filepath.EvalSymlinks(path) - if err != nil { - t.Fatal(err) - } return path } diff --git a/common/platform/filesystem/file.go b/common/platform/filesystem/file.go index 443235975..4de0291da 100644 --- a/common/platform/filesystem/file.go +++ b/common/platform/filesystem/file.go @@ -2,7 +2,6 @@ package filesystem import ( "errors" - "fmt" "io" "os" "path/filepath" @@ -49,7 +48,15 @@ func getAssetFileLocation(file string) (string, os.FileInfo, error) { if err != nil { return "", nil, err } - return ResolveRegularFile(platform.GetAssetLocation(local)) + path := platform.GetAssetLocation(local) + info, err := os.Stat(path) + if err != nil { + return "", nil, err + } + if !info.Mode().IsRegular() { + return "", nil, errors.New("asset is not a regular file") + } + return path, info, nil } func ReadCert(file string) ([]byte, error) { @@ -59,52 +66,29 @@ func ReadCert(file string) ([]byte, error) { return ReadFile(platform.GetCertLocation(file)) } -// ResolveLuaFile finds a local .lua script and returns its resolved absolute path. +// ResolveLuaFile finds a local .lua script and returns its absolute path. // Relative paths: XRAY_LOCATION_CONFDIR > XRAY_LOCATION_CONFIG > working dir > executable dir. -func ResolveLuaFile(path string) (resolved string, err error) { +func ResolveLuaFile(path string) (string, error) { + if filepath.Ext(path) != ".lua" { + return "", errors.New("Lua file extension must be .lua") + } if filepath.IsAbs(path) { - resolved, _, err = ResolveRegularFile(path) - } else { - for _, dir := range []string{ - platform.GetConfDirPath(), - platform.NewEnvFlag(platform.ConfigLocation).GetValue(func() string { return "" }), - ".", - platform.GetExecutableDir(), - } { - if dir != "" { - if resolved, _, err = ResolveRegularFile(filepath.Join(dir, path)); err == nil || !errors.Is(err, os.ErrNotExist) { - break - } + return path, nil + } + for _, dir := range []string{ + platform.GetConfDirPath(), + platform.NewEnvFlag(platform.ConfigLocation).GetValue(func() string { return "" }), + ".", + platform.GetExecutableDir(), + } { + if dir != "" { + resolved := filepath.Join(dir, path) + if _, err := os.Stat(resolved); err == nil { + return filepath.Abs(resolved) + } else if !os.IsNotExist(err) { + return "", err } } } - if err != nil { - return "", err - } - if filepath.Ext(resolved) != ".lua" { - return "", errors.New("Lua file extension must be .lua") - } - return resolved, nil -} - -// ResolveRegularFile returns an absolute path and metadata of a regular file. -// Symlinks are resolved when possible; otherwise the original path is kept. -func ResolveRegularFile(path string) (string, os.FileInfo, error) { - path, err := filepath.Abs(path) - if err != nil { - return "", nil, fmt.Errorf("failed to resolve file path: %w", err) - } - // Best effort: EvalSymlinks may fail when Windows junctions are involved. - if resolved, err := filepath.EvalSymlinks(path); err == nil { - path = resolved - } - info, err := os.Stat(path) - if err != nil { - return "", nil, fmt.Errorf("failed to inspect file %q: %w", path, err) - } - if !info.Mode().IsRegular() { - return "", nil, fmt.Errorf("file is not a regular file: %s", path) - } - // Hard links are not handled. - return path, info, nil + return "", os.ErrNotExist } diff --git a/common/platform/filesystem/file_test.go b/common/platform/filesystem/file_test.go index 280b8c793..89a18074a 100644 --- a/common/platform/filesystem/file_test.go +++ b/common/platform/filesystem/file_test.go @@ -4,8 +4,6 @@ import ( "errors" "os" "path/filepath" - "runtime" - "strings" "testing" "github.com/xtls/xray-core/common" @@ -38,8 +36,9 @@ func TestResolveAssetRejectsInvalidPath(t *testing.T) { } func TestResolveLuaFile(t *testing.T) { - workingDir := t.TempDir() - t.Chdir(workingDir) + t.Chdir(t.TempDir()) + workingDir, err := os.Getwd() + common.Must(err) executable, err := os.Executable() common.Must(err) file, err := os.CreateTemp(filepath.Dir(executable), "lua-*.lua") @@ -59,10 +58,6 @@ func TestResolveLuaFile(t *testing.T) { for _, path := range paths[:3] { common.Must(os.WriteFile(path, nil, 0o600)) } - for i, path := range paths { - paths[i], err = filepath.EvalSymlinks(path) - common.Must(err) - } if got, err := ResolveLuaFile(paths[2]); err != nil || got != paths[2] { t.Fatalf("absolute path = %q, %v; want %q", got, err, paths[2]) } @@ -79,46 +74,4 @@ func TestResolveLuaFile(t *testing.T) { if _, err := ResolveLuaFile(name); !errors.Is(err, os.ErrNotExist) { t.Fatalf("missing file error = %v", err) } - - t.Setenv(platform.ConfdirLocation, filepath.Dir(paths[0])) - t.Setenv(platform.ConfigLocation, filepath.Dir(paths[1])) - common.Must(os.Mkdir(paths[0], 0o700)) - common.Must(os.WriteFile(paths[1], nil, 0o600)) - for _, path := range []string{"", name, filepath.Join(t.TempDir(), name)} { - if _, err := ResolveLuaFile(path); err == nil { - t.Fatalf("accepted invalid path %q", path) - } - } -} - -func TestResolveLuaFileSymlink(t *testing.T) { - for _, tc := range []struct { - link, target string - valid bool - }{ - {"alias.lua", "data.dat", false}, - {"alias.dat", "script.lua", true}, - } { - t.Run(tc.link, func(t *testing.T) { - dir, err := filepath.EvalSymlinks(t.TempDir()) - common.Must(err) - target := filepath.Join(dir, tc.target) - common.Must(os.WriteFile(target, nil, 0o600)) - link := filepath.Join(dir, tc.link) - if err := os.Symlink(tc.target, link); err != nil { - if runtime.GOOS == "windows" { - t.Skipf("cannot create symlinks: %v", err) - } - t.Fatal(err) - } - got, err := ResolveLuaFile(link) - if tc.valid { - if err != nil || got != target { - t.Fatalf("ResolveLuaFile(%q) = %q, %v; want %q", link, got, err, target) - } - } else if err == nil || got != "" || !strings.Contains(err.Error(), "Lua file extension must be .lua") { - t.Fatalf("ResolveLuaFile(%q) = %q, %v; want .lua extension error", link, got, err) - } - }) - } } diff --git a/main/commands/all/lua/sign.go b/main/commands/all/lua/sign.go index 233bd9111..cf23176f3 100644 --- a/main/commands/all/lua/sign.go +++ b/main/commands/all/lua/sign.go @@ -5,7 +5,6 @@ import ( "path/filepath" xlua "github.com/xtls/xray-core/common/lua" - "github.com/xtls/xray-core/common/platform/filesystem" "github.com/xtls/xray-core/main/commands/base" ) @@ -33,15 +32,14 @@ func executeSign(cmd *base.Command, args []string) { cmd.Usage() } - input, info, err := filesystem.ResolveRegularFile(args[0]) + if filepath.Ext(args[0]) != ".lua" { + base.Fatalf("Lua file extension must be .lua") + } + info, err := os.Stat(args[0]) if err != nil { base.Fatalf("failed to inspect Lua file: %s", err) } - if filepath.Ext(input) != ".lua" { - base.Fatalf("Lua file extension must be .lua") - } - - code, err := os.ReadFile(input) + code, err := os.ReadFile(args[0]) if err != nil { base.Fatalf("failed to read Lua file: %s", err) } @@ -59,7 +57,7 @@ func executeSign(cmd *base.Command, args []string) { } output := *signOutput if output == "" { - output = input + output = args[0] } if err := writeSignedFile(output, signed, info.Mode().Perm()); err != nil { base.Fatalf("failed to write signed Lua file: %s", err) @@ -67,8 +65,7 @@ func executeSign(cmd *base.Command, args []string) { } func writeSignedFile(path string, code []byte, mode os.FileMode) error { - if resolved, info, err := filesystem.ResolveRegularFile(path); err == nil { - path = resolved + if info, err := os.Stat(path); err == nil { mode = info.Mode().Perm() } else if !os.IsNotExist(err) { return err diff --git a/main/confloader/external/external.go b/main/confloader/external/external.go index 02ac400ee..340bc9f2f 100644 --- a/main/confloader/external/external.go +++ b/main/confloader/external/external.go @@ -14,7 +14,6 @@ import ( "github.com/xtls/xray-core/common/buf" "github.com/xtls/xray-core/common/errors" - "github.com/xtls/xray-core/common/platform/filesystem" "github.com/xtls/xray-core/common/utils" "github.com/xtls/xray-core/main/commands/base" "github.com/xtls/xray-core/main/confloader" @@ -59,14 +58,10 @@ func readConfigFile(file *os.File) ([]byte, error) { return nil, err } if info.Mode().IsRegular() { - path, _, err := filesystem.ResolveRegularFile(file.Name()) - if err != nil { - return nil, err - } - switch strings.ToLower(filepath.Ext(path)) { + switch strings.ToLower(filepath.Ext(file.Name())) { case ".jsonc", ".json", ".yml", ".yaml", ".toml", ".pb", ".protobuf": default: - return nil, errors.New("unsupported config file extension: ", path) + return nil, errors.New("unsupported config file extension: ", file.Name()) } } return io.ReadAll(file)