path.go 3.9 KB

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