github.com/metacubex/mihomo@v1.18.5/constant/path.go (about) 1 package constant 2 3 import ( 4 "crypto/md5" 5 "encoding/hex" 6 "os" 7 P "path" 8 "path/filepath" 9 "strconv" 10 "strings" 11 ) 12 13 const Name = "mihomo" 14 15 var ( 16 GeositeName = "GeoSite.dat" 17 GeoipName = "GeoIP.dat" 18 ASNName = "ASN.mmdb" 19 ) 20 21 // Path is used to get the configuration path 22 // 23 // on Unix systems, `$HOME/.config/mihomo`. 24 // on Windows, `%USERPROFILE%/.config/mihomo`. 25 var Path = func() *path { 26 homeDir, err := os.UserHomeDir() 27 if err != nil { 28 homeDir, _ = os.Getwd() 29 } 30 allowUnsafePath, _ := strconv.ParseBool(os.Getenv("SKIP_SAFE_PATH_CHECK")) 31 homeDir = P.Join(homeDir, ".config", Name) 32 33 if _, err = os.Stat(homeDir); err != nil { 34 if configHome, ok := os.LookupEnv("XDG_CONFIG_HOME"); ok { 35 homeDir = P.Join(configHome, Name) 36 } 37 } 38 39 return &path{homeDir: homeDir, configFile: "config.yaml", allowUnsafePath: allowUnsafePath} 40 }() 41 42 type path struct { 43 homeDir string 44 configFile string 45 allowUnsafePath bool 46 } 47 48 // SetHomeDir is used to set the configuration path 49 func SetHomeDir(root string) { 50 Path.homeDir = root 51 } 52 53 // SetConfig is used to set the configuration file 54 func SetConfig(file string) { 55 Path.configFile = file 56 } 57 58 func (p *path) HomeDir() string { 59 return p.homeDir 60 } 61 62 func (p *path) Config() string { 63 return p.configFile 64 } 65 66 // Resolve return a absolute path or a relative path with homedir 67 func (p *path) Resolve(path string) string { 68 if !filepath.IsAbs(path) { 69 return filepath.Join(p.HomeDir(), path) 70 } 71 return path 72 } 73 74 // IsSafePath return true if path is a subpath of homedir 75 func (p *path) IsSafePath(path string) bool { 76 if p.allowUnsafePath { 77 return true 78 } 79 homedir := p.HomeDir() 80 path = p.Resolve(path) 81 rel, err := filepath.Rel(homedir, path) 82 if err != nil { 83 return false 84 } 85 86 return !strings.Contains(rel, "..") 87 } 88 89 func (p *path) GetPathByHash(prefix, name string) string { 90 hash := md5.Sum([]byte(name)) 91 filename := hex.EncodeToString(hash[:]) 92 return filepath.Join(p.HomeDir(), prefix, filename) 93 } 94 95 func (p *path) MMDB() string { 96 files, err := os.ReadDir(p.homeDir) 97 if err != nil { 98 return "" 99 } 100 for _, fi := range files { 101 if fi.IsDir() { 102 // 目录则直接跳过 103 continue 104 } else { 105 if strings.EqualFold(fi.Name(), "Country.mmdb") || 106 strings.EqualFold(fi.Name(), "geoip.db") || 107 strings.EqualFold(fi.Name(), "geoip.metadb") { 108 GeoipName = fi.Name() 109 return P.Join(p.homeDir, fi.Name()) 110 } 111 } 112 } 113 return P.Join(p.homeDir, "geoip.metadb") 114 } 115 116 func (p *path) ASN() string { 117 files, err := os.ReadDir(p.homeDir) 118 if err != nil { 119 return "" 120 } 121 for _, fi := range files { 122 if fi.IsDir() { 123 // 目录则直接跳过 124 continue 125 } else { 126 if strings.EqualFold(fi.Name(), "ASN.mmdb") { 127 ASNName = fi.Name() 128 return P.Join(p.homeDir, fi.Name()) 129 } 130 } 131 } 132 return P.Join(p.homeDir, ASNName) 133 } 134 135 func (p *path) OldCache() string { 136 return P.Join(p.homeDir, ".cache") 137 } 138 139 func (p *path) Cache() string { 140 return P.Join(p.homeDir, "cache.db") 141 } 142 143 func (p *path) GeoIP() string { 144 files, err := os.ReadDir(p.homeDir) 145 if err != nil { 146 return "" 147 } 148 for _, fi := range files { 149 if fi.IsDir() { 150 // 目录则直接跳过 151 continue 152 } else { 153 if strings.EqualFold(fi.Name(), "GeoIP.dat") { 154 GeoipName = fi.Name() 155 return P.Join(p.homeDir, fi.Name()) 156 } 157 } 158 } 159 return P.Join(p.homeDir, "GeoIP.dat") 160 } 161 162 func (p *path) GeoSite() string { 163 files, err := os.ReadDir(p.homeDir) 164 if err != nil { 165 return "" 166 } 167 for _, fi := range files { 168 if fi.IsDir() { 169 // 目录则直接跳过 170 continue 171 } else { 172 if strings.EqualFold(fi.Name(), "GeoSite.dat") { 173 GeositeName = fi.Name() 174 return P.Join(p.homeDir, fi.Name()) 175 } 176 } 177 } 178 return P.Join(p.homeDir, "GeoSite.dat") 179 } 180 181 func (p *path) GetAssetLocation(file string) string { 182 return P.Join(p.homeDir, file) 183 } 184 185 func (p *path) GetExecutableFullPath() string { 186 exePath, err := os.Executable() 187 if err != nil { 188 return "mihomo" 189 } 190 res, _ := filepath.EvalSymlinks(exePath) 191 return res 192 }