1
0
mirror of https://github.com/MetaCubeX/mihomo.git synced 2025-09-19 20:15:59 +08:00

chore: allow setting addition safePaths by environment variable SAFE_PATHS

package managers can allow for pre-defined safe paths without disabling the entire security check feature
for https://github.com/MetaCubeX/mihomo/issues/2004
This commit is contained in:
wwqgtxx
2025-05-01 12:33:21 +08:00
parent 7e7016b567
commit 791ea5e568
2 changed files with 61 additions and 7 deletions

View File

@ -37,13 +37,23 @@ var Path = func() *path {
} }
} }
return &path{homeDir: homeDir, configFile: "config.yaml", allowUnsafePath: allowUnsafePath} var safePaths []string
for _, safePath := range strings.Split(os.Getenv("SAFE_PATHS"), ":") {
safePath = strings.TrimSpace(safePath)
if len(safePath) == 0 {
continue
}
safePaths = append(safePaths, safePath)
}
return &path{homeDir: homeDir, configFile: "config.yaml", allowUnsafePath: allowUnsafePath, safePaths: safePaths}
}() }()
type path struct { type path struct {
homeDir string homeDir string
configFile string configFile string
allowUnsafePath bool allowUnsafePath bool
safePaths []string
} }
// SetHomeDir is used to set the configuration path // SetHomeDir is used to set the configuration path
@ -72,19 +82,22 @@ func (p *path) Resolve(path string) string {
return path return path
} }
// IsSafePath return true if path is a subpath of homedir // IsSafePath return true if path is a subpath of homedir (or in the SAFE_PATHS environment variable)
func (p *path) IsSafePath(path string) bool { func (p *path) IsSafePath(path string) bool {
if p.allowUnsafePath || features.CMFA { if p.allowUnsafePath || features.CMFA {
return true return true
} }
homedir := p.HomeDir() homedir := p.HomeDir()
path = p.Resolve(path) path = p.Resolve(path)
rel, err := filepath.Rel(homedir, path) safePaths := append([]string{homedir}, p.safePaths...) // add homedir to safePaths
if err != nil { for _, safePath := range safePaths {
return false if rel, err := filepath.Rel(safePath, path); err == nil {
if filepath.IsLocal(rel) {
return true
}
}
} }
return false
return filepath.IsLocal(rel)
} }
func (p *path) GetPathByHash(prefix, name string) string { func (p *path) GetPathByHash(prefix, name string) string {

41
constant/path_test.go Normal file
View File

@ -0,0 +1,41 @@
package constant
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestPath(t *testing.T) {
assert.False(t, (&path{}).IsSafePath("/usr/share/metacubexd/"))
assert.True(t, (&path{
safePaths: []string{"/usr/share/metacubexd"},
}).IsSafePath("/usr/share/metacubexd/"))
assert.False(t, (&path{}).IsSafePath("../metacubexd/"))
assert.True(t, (&path{
homeDir: "/usr/share/mihomo",
safePaths: []string{"/usr/share/metacubexd"},
}).IsSafePath("../metacubexd/"))
assert.False(t, (&path{
homeDir: "/usr/share/mihomo",
safePaths: []string{"/usr/share/ycad"},
}).IsSafePath("../metacubexd/"))
assert.False(t, (&path{}).IsSafePath("/opt/mykeys/key1.key"))
assert.True(t, (&path{
safePaths: []string{"/opt/mykeys"},
}).IsSafePath("/opt/mykeys/key1.key"))
assert.True(t, (&path{
safePaths: []string{"/opt/mykeys/"},
}).IsSafePath("/opt/mykeys/key1.key"))
assert.True(t, (&path{
safePaths: []string{"/opt/mykeys/key1.key"},
}).IsSafePath("/opt/mykeys/key1.key"))
assert.True(t, (&path{}).IsSafePath("key1.key"))
assert.True(t, (&path{}).IsSafePath("./key1.key"))
assert.True(t, (&path{}).IsSafePath("./mykey/key1.key"))
assert.True(t, (&path{}).IsSafePath("./mykey/../key1.key"))
assert.False(t, (&path{}).IsSafePath("./mykey/../../key1.key"))
}