github.com/kelleygo/clashcore@v1.0.2/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 = "yiclashcore"
    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/yiclashcore`.
    24  // on Windows, `%USERPROFILE%/.config/yiclashcore`.
    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 "yiclashcore"
   189  	}
   190  	res, _ := filepath.EvalSymlinks(exePath)
   191  	return res
   192  }