package service import ( "encoding/json" "os" "s-ui/database" "s-ui/database/model" "s-ui/logger" "s-ui/util/common" "strconv" "strings" "time" "gorm.io/gorm" ) var defaultValueMap = map[string]string{ "webListen": "", "webDomain": "", "webPort": "2095", "secret": common.Random(32), "webCertFile": "", "webKeyFile": "", "webPath": "/app/", "webURI": "", "sessionMaxAge": "0", "trafficAge": "30", "timeLocation": "Asia/Tehran", "subListen": "", "subPort": "2096", "subPath": "/sub/", "subDomain": "", "subCertFile": "", "subKeyFile": "", "subUpdates": "12", "subEncode": "true", "subShowInfo": "false", "subURI": "", } type SettingService struct { } func (s *SettingService) GetAllSetting() (*map[string]string, error) { db := database.GetDB() settings := make([]*model.Setting, 0) err := db.Model(model.Setting{}).Find(&settings).Error if err != nil { return nil, err } allSetting := map[string]string{} for _, setting := range settings { allSetting[setting.Key] = setting.Value } for key, defaultValue := range defaultValueMap { if _, exists := allSetting[key]; !exists { err = s.saveSetting(key, defaultValue) if err != nil { return nil, err } allSetting[key] = defaultValue } } // Due to security principles delete(allSetting, "webSecret") return &allSetting, nil } func (s *SettingService) ResetSettings() error { db := database.GetDB() return db.Where("1 = 1").Delete(model.Setting{}).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) 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) 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) 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) GetListen() (string, error) { return s.getString("webListen") } func (s *SettingService) GetWebDomain() (string, error) { return s.getString("webDomain") } 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) GetWebPath() (string, error) { webPath, err := s.getString("webPath") if err != nil { return "", err } if !strings.HasPrefix(webPath, "/") { webPath = "/" + webPath } if !strings.HasSuffix(webPath, "/") { webPath += "/" } return webPath, nil } func (s *SettingService) SetWebPath(webPath string) error { if !strings.HasPrefix(webPath, "/") { webPath = "/" + webPath } if !strings.HasSuffix(webPath, "/") { webPath += "/" } return s.setString("webPath", webPath) } 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) GetSessionMaxAge() (int, error) { return s.getInt("sessionMaxAge") } func (s *SettingService) GetTrafficAge() (int, error) { return s.getInt("trafficAge") } 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) GetSubListen() (string, error) { return s.getString("subListen") } func (s *SettingService) GetSubPort() (int, error) { return s.getInt("subPort") } func (s *SettingService) SetSubPort(subPort int) error { return s.setInt("subPort", 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) SetSubPath(subPath string) error { if !strings.HasPrefix(subPath, "/") { subPath = "/" + subPath } if !strings.HasSuffix(subPath, "/") { subPath += "/" } return s.setString("subPath", subPath) } 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) GetSubEncode() (bool, error) { return s.getBool("subEncode") } func (s *SettingService) GetSubShowInfo() (bool, error) { return s.getBool("subShowInfo") } func (s *SettingService) GetSubURI() (string, error) { return s.getString("subURI") } func (s *SettingService) GetFinalSubURI(host string) (string, error) { allSetting, err := s.GetAllSetting() if err != nil { return "", err } SubURI := (*allSetting)["subURI"] if SubURI != "" { return SubURI, nil } protocol := "http" if (*allSetting)["subKeyFile"] != "" && (*allSetting)["subCertFile"] != "" { protocol = "https" } if (*allSetting)["subDomain"] != "" { host = (*allSetting)["subDomain"] } port := ":" + (*allSetting)["subPort"] if (port == "80" && protocol == "http") || (port == "443" && protocol == "https") { port = "" } return protocol + "://" + host + port + (*allSetting)["subPath"], nil } func (s *SettingService) Save(tx *gorm.DB, changes []model.Changes) error { var err error for _, change := range changes { key := change.Key var obj string json.Unmarshal(change.Obj, &obj) // Secure file existance check if obj != "" && (key == "webCertFile" || key == "webKeyFile" || key == "subCertFile" || key == "subKeyFile") { err = s.fileExists(obj) if err != nil { return common.NewError(" -> ", obj, " is not exists") } } // Correct Pathes start and ends with `/` if key == "webPath" || key == "subPath" { if !strings.HasPrefix(obj, "/") { obj = "/" + obj } if !strings.HasSuffix(obj, "/") { obj += "/" } } err = tx.Model(model.Setting{}).Where("key = ?", key).Update("value", obj).Error if err != nil { return err } } return err } func (s *SettingService) fileExists(path string) error { _, err := os.Stat(path) return err }