| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526 | package serviceimport (	_ "embed"	"encoding/json"	"errors"	"fmt"	"reflect"	"strconv"	"strings"	"time"	"x-ui/database"	"x-ui/database/model"	"x-ui/logger"	"x-ui/util/common"	"x-ui/util/random"	"x-ui/util/reflect_util"	"x-ui/web/entity")//go:embed config.jsonvar xrayTemplateConfig stringvar defaultValueMap = map[string]string{	"xrayTemplateConfig": xrayTemplateConfig,	"webListen":          "",	"webDomain":          "",	"webPort":            "2053",	"webCertFile":        "",	"webKeyFile":         "",	"secret":             random.Seq(32),	"webBasePath":        "/",	"sessionMaxAge":      "0",	"pageSize":           "0",	"expireDiff":         "0",	"trafficDiff":        "0",	"remarkModel":        "-ieo",	"timeLocation":       "Asia/Tehran",	"tgBotEnable":        "false",	"tgBotToken":         "",	"tgBotProxy":         "",	"tgBotChatId":        "",	"tgRunTime":          "@daily",	"tgBotBackup":        "false",	"tgBotLoginNotify":   "true",	"tgCpu":              "0",	"tgLang":             "en-US",	"secretEnable":       "false",	"subEnable":          "false",	"subListen":          "",	"subPort":            "2096",	"subPath":            "/sub/",	"subDomain":          "",	"subCertFile":        "",	"subKeyFile":         "",	"subUpdates":         "12",	"subEncrypt":         "true",	"subShowInfo":        "true",	"subURI":             "",	"datepicker":         "gregorian",}type SettingService struct {}func (s *SettingService) GetDefaultJsonConfig() (interface{}, error) {	var jsonData interface{}	err := json.Unmarshal([]byte(xrayTemplateConfig), &jsonData)	if err != nil {		return nil, err	}	return jsonData, nil}func (s *SettingService) GetAllSetting() (*entity.AllSetting, error) {	db := database.GetDB()	settings := make([]*model.Setting, 0)	err := db.Model(model.Setting{}).Not("key = ?", "xrayTemplateConfig").Find(&settings).Error	if err != nil {		return nil, err	}	allSetting := &entity.AllSetting{}	t := reflect.TypeOf(allSetting).Elem()	v := reflect.ValueOf(allSetting).Elem()	fields := reflect_util.GetFields(t)	setSetting := func(key, value string) (err error) {		defer func() {			panicErr := recover()			if panicErr != nil {				err = errors.New(fmt.Sprint(panicErr))			}		}()		var found bool		var field reflect.StructField		for _, f := range fields {			if f.Tag.Get("json") == key {				field = f				found = true				break			}		}		if !found {			// Some settings are automatically generated, no need to return to the front end to modify the user			return nil		}		fieldV := v.FieldByName(field.Name)		switch t := fieldV.Interface().(type) {		case int:			n, err := strconv.ParseInt(value, 10, 64)			if err != nil {				return err			}			fieldV.SetInt(n)		case string:			fieldV.SetString(value)		case bool:			fieldV.SetBool(value == "true")		default:			return common.NewErrorf("unknown field %v type %v", key, t)		}		return	}	keyMap := map[string]bool{}	for _, setting := range settings {		err := setSetting(setting.Key, setting.Value)		if err != nil {			return nil, err		}		keyMap[setting.Key] = true	}	for key, value := range defaultValueMap {		if keyMap[key] {			continue		}		err := setSetting(key, value)		if err != nil {			return nil, err		}	}	return allSetting, nil}func (s *SettingService) ResetSettings() error {	db := database.GetDB()	err := db.Where("1 = 1").Delete(model.Setting{}).Error	if err != nil {		return err	}	return db.Model(model.User{}).		Where("1 = 1").		Update("login_secret", "").Error}func (s *SettingService) getSetting(key string) (*model.Setting, error) {	db := database.GetDB()	setting := &model.Setting{}	err := db.Model(model.Setting{}).Where("key = ?", key).First(setting).Error	if err != nil {		return nil, err	}	return setting, nil}func (s *SettingService) saveSetting(key string, value string) error {	setting, err := s.getSetting(key)	db := database.GetDB()	if database.IsNotFound(err) {		return db.Create(&model.Setting{			Key:   key,			Value: value,		}).Error	} else if err != nil {		return err	}	setting.Key = key	setting.Value = value	return db.Save(setting).Error}func (s *SettingService) getString(key string) (string, error) {	setting, err := s.getSetting(key)	if database.IsNotFound(err) {		value, ok := defaultValueMap[key]		if !ok {			return "", common.NewErrorf("key <%v> not in defaultValueMap", key)		}		return value, nil	} else if err != nil {		return "", err	}	return setting.Value, nil}func (s *SettingService) setString(key string, value string) error {	return s.saveSetting(key, value)}func (s *SettingService) getBool(key string) (bool, error) {	str, err := s.getString(key)	if err != nil {		return false, err	}	return strconv.ParseBool(str)}func (s *SettingService) setBool(key string, value bool) error {	return s.setString(key, strconv.FormatBool(value))}func (s *SettingService) getInt(key string) (int, error) {	str, err := s.getString(key)	if err != nil {		return 0, err	}	return strconv.Atoi(str)}func (s *SettingService) setInt(key string, value int) error {	return s.setString(key, strconv.Itoa(value))}func (s *SettingService) GetXrayConfigTemplate() (string, error) {	return s.getString("xrayTemplateConfig")}func (s *SettingService) GetListen() (string, error) {	return s.getString("webListen")}func (s *SettingService) GetWebDomain() (string, error) {	return s.getString("webDomain")}func (s *SettingService) GetTgBotToken() (string, error) {	return s.getString("tgBotToken")}func (s *SettingService) SetTgBotToken(token string) error {	return s.setString("tgBotToken", token)}func (s *SettingService) GetTgBotProxy() (string, error) {	return s.getString("tgBotProxy")}func (s *SettingService) SetTgBotProxy(token string) error {	return s.setString("tgBotProxy", token)}func (s *SettingService) GetTgBotChatId() (string, error) {	return s.getString("tgBotChatId")}func (s *SettingService) SetTgBotChatId(chatIds string) error {	return s.setString("tgBotChatId", chatIds)}func (s *SettingService) GetTgbotenabled() (bool, error) {	return s.getBool("tgBotEnable")}func (s *SettingService) SetTgbotenabled(value bool) error {	return s.setBool("tgBotEnable", value)}func (s *SettingService) GetTgbotRuntime() (string, error) {	return s.getString("tgRunTime")}func (s *SettingService) SetTgbotRuntime(time string) error {	return s.setString("tgRunTime", time)}func (s *SettingService) GetTgBotBackup() (bool, error) {	return s.getBool("tgBotBackup")}func (s *SettingService) GetTgBotLoginNotify() (bool, error) {	return s.getBool("tgBotLoginNotify")}func (s *SettingService) GetTgCpu() (int, error) {	return s.getInt("tgCpu")}func (s *SettingService) GetTgLang() (string, error) {	return s.getString("tgLang")}func (s *SettingService) GetPort() (int, error) {	return s.getInt("webPort")}func (s *SettingService) SetPort(port int) error {	return s.setInt("webPort", port)}func (s *SettingService) GetCertFile() (string, error) {	return s.getString("webCertFile")}func (s *SettingService) GetKeyFile() (string, error) {	return s.getString("webKeyFile")}func (s *SettingService) GetExpireDiff() (int, error) {	return s.getInt("expireDiff")}func (s *SettingService) GetTrafficDiff() (int, error) {	return s.getInt("trafficDiff")}func (s *SettingService) GetSessionMaxAge() (int, error) {	return s.getInt("sessionMaxAge")}func (s *SettingService) GetRemarkModel() (string, error) {	return s.getString("remarkModel")}func (s *SettingService) GetSecretStatus() (bool, error) {	return s.getBool("secretEnable")}func (s *SettingService) SetSecretStatus(value bool) error {	return s.setBool("secretEnable", value)}func (s *SettingService) GetSecret() ([]byte, error) {	secret, err := s.getString("secret")	if secret == defaultValueMap["secret"] {		err := s.saveSetting("secret", secret)		if err != nil {			logger.Warning("save secret failed:", err)		}	}	return []byte(secret), err}func (s *SettingService) GetBasePath() (string, error) {	basePath, err := s.getString("webBasePath")	if err != nil {		return "", err	}	if !strings.HasPrefix(basePath, "/") {		basePath = "/" + basePath	}	if !strings.HasSuffix(basePath, "/") {		basePath += "/"	}	return basePath, nil}func (s *SettingService) GetTimeLocation() (*time.Location, error) {	l, err := s.getString("timeLocation")	if err != nil {		return nil, err	}	location, err := time.LoadLocation(l)	if err != nil {		defaultLocation := defaultValueMap["timeLocation"]		logger.Errorf("location <%v> not exist, using default location: %v", l, defaultLocation)		return time.LoadLocation(defaultLocation)	}	return location, nil}func (s *SettingService) GetSubEnable() (bool, error) {	return s.getBool("subEnable")}func (s *SettingService) GetSubListen() (string, error) {	return s.getString("subListen")}func (s *SettingService) GetSubPort() (int, error) {	return s.getInt("subPort")}func (s *SettingService) GetSubPath() (string, error) {	subPath, err := s.getString("subPath")	if err != nil {		return "", err	}	if !strings.HasPrefix(subPath, "/") {		subPath = "/" + subPath	}	if !strings.HasSuffix(subPath, "/") {		subPath += "/"	}	return subPath, nil}func (s *SettingService) GetSubDomain() (string, error) {	return s.getString("subDomain")}func (s *SettingService) GetSubCertFile() (string, error) {	return s.getString("subCertFile")}func (s *SettingService) GetSubKeyFile() (string, error) {	return s.getString("subKeyFile")}func (s *SettingService) GetSubUpdates() (int, error) {	return s.getInt("subUpdates")}func (s *SettingService) GetSubEncrypt() (bool, error) {	return s.getBool("subEncrypt")}func (s *SettingService) GetSubShowInfo() (bool, error) {	return s.getBool("subShowInfo")}func (s *SettingService) GetSubURI() (string, error) {	return s.getString("subURI")}func (s *SettingService) GetDatepicker() (string, error) {	return s.getString("datepicker")}func (s *SettingService) GetPageSize() (int, error) {	return s.getInt("pageSize")}func (s *SettingService) UpdateAllSetting(allSetting *entity.AllSetting) error {	if err := allSetting.CheckValid(); err != nil {		return err	}	v := reflect.ValueOf(allSetting).Elem()	t := reflect.TypeOf(allSetting).Elem()	fields := reflect_util.GetFields(t)	errs := make([]error, 0)	for _, field := range fields {		key := field.Tag.Get("json")		fieldV := v.FieldByName(field.Name)		value := fmt.Sprint(fieldV.Interface())		err := s.saveSetting(key, value)		if err != nil {			errs = append(errs, err)		}	}	return common.Combine(errs...)}func (s *SettingService) GetDefaultXrayConfig() (interface{}, error) {	var jsonData interface{}	err := json.Unmarshal([]byte(xrayTemplateConfig), &jsonData)	if err != nil {		return nil, err	}	return jsonData, nil}func (s *SettingService) GetDefaultSettings(host string) (interface{}, error) {	type settingFunc func() (interface{}, error)	settings := map[string]settingFunc{		"expireDiff":  func() (interface{}, error) { return s.GetExpireDiff() },		"trafficDiff": func() (interface{}, error) { return s.GetTrafficDiff() },		"pageSize":    func() (interface{}, error) { return s.GetPageSize() },		"defaultCert": func() (interface{}, error) { return s.GetCertFile() },		"defaultKey":  func() (interface{}, error) { return s.GetKeyFile() },		"tgBotEnable": func() (interface{}, error) { return s.GetTgbotenabled() },		"subEnable":   func() (interface{}, error) { return s.GetSubEnable() },		"subURI":      func() (interface{}, error) { return s.GetSubURI() },		"remarkModel": func() (interface{}, error) { return s.GetRemarkModel() },		"datepicker":  func() (interface{}, error) { return s.GetDatepicker() },	}	result := make(map[string]interface{})	for key, fn := range settings {		value, err := fn()		if err != nil {			return "", err		}		result[key] = value	}	if result["subEnable"].(bool) && result["subURI"].(string) == "" {		subURI := ""		subPort, _ := s.GetSubPort()		subPath, _ := s.GetSubPath()		subDomain, _ := s.GetSubDomain()		subKeyFile, _ := s.GetSubKeyFile()		subCertFile, _ := s.GetSubCertFile()		subTLS := false		if subKeyFile != "" && subCertFile != "" {			subTLS = true		}		if subDomain == "" {			subDomain = strings.Split(host, ":")[0]		}		if subTLS {			subURI = "https://"		} else {			subURI = "http://"		}		if (subPort == 443 && subTLS) || (subPort == 80 && !subTLS) {			subURI += subDomain		} else {			subURI += fmt.Sprintf("%s:%d", subDomain, subPort)		}		if subPath[0] == byte('/') {			subURI += subPath		} else {			subURI += "/" + subPath		}		result["subURI"] = subURI	}	return result, nil}
 |