setting.go 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477
  1. package service
  2. import (
  3. _ "embed"
  4. "encoding/json"
  5. "errors"
  6. "fmt"
  7. "net"
  8. "net/http"
  9. "os"
  10. "reflect"
  11. "regexp"
  12. "strconv"
  13. "strings"
  14. "time"
  15. "github.com/google/uuid"
  16. "github.com/xlzd/gotp"
  17. "gorm.io/gorm"
  18. "github.com/mhsanaei/3x-ui/v3/internal/config"
  19. "github.com/mhsanaei/3x-ui/v3/internal/database"
  20. "github.com/mhsanaei/3x-ui/v3/internal/database/model"
  21. "github.com/mhsanaei/3x-ui/v3/internal/logger"
  22. "github.com/mhsanaei/3x-ui/v3/internal/util/common"
  23. "github.com/mhsanaei/3x-ui/v3/internal/util/netproxy"
  24. "github.com/mhsanaei/3x-ui/v3/internal/util/random"
  25. "github.com/mhsanaei/3x-ui/v3/internal/util/reflect_util"
  26. "github.com/mhsanaei/3x-ui/v3/internal/web/entity"
  27. "github.com/mhsanaei/3x-ui/v3/internal/xray"
  28. )
  29. //go:embed config.json
  30. var xrayTemplateConfig string
  31. const (
  32. DefaultSubClashUserAgentRegex = `(?i)(clash|mihomo)`
  33. DefaultSubJsonUserAgentRegex = ``
  34. DefaultRemarkTemplate = "{{INBOUND}}-{{EMAIL}}|📊{{TRAFFIC_LEFT}}|⏳{{DAYS_LEFT}}D"
  35. maxRegexLength = 2048
  36. )
  37. var defaultValueMap = map[string]string{
  38. "xrayTemplateConfig": xrayTemplateConfig,
  39. "webListen": "",
  40. "webDomain": "",
  41. "webPort": "2053",
  42. "webCertFile": "",
  43. "webKeyFile": "",
  44. "secret": random.Seq(32),
  45. "panelGuid": uuid.NewString(),
  46. "apiToken": "",
  47. // Node mTLS material (opt-in). All default empty: the CA + master client
  48. // cert are minted lazily on first use, and the node-side trust CA is pasted
  49. // in by the operator. Kept out of entity.AllSetting so private keys never
  50. // reach the settings UI/export.
  51. "nodeMtlsCaCertPem": "",
  52. "nodeMtlsCaKeyPem": "",
  53. "nodeMtlsClientCertPem": "",
  54. "nodeMtlsClientKeyPem": "",
  55. "nodeMtlsClientCAPem": "",
  56. "webBasePath": normalizeBasePath(getEnv("XUI_INIT_WEB_BASE_PATH", "/")),
  57. "sessionMaxAge": "360",
  58. "trustedProxyCIDRs": "127.0.0.1/32,::1/128",
  59. "pageSize": "25",
  60. "expireDiff": "0",
  61. "trafficDiff": "0",
  62. "remarkTemplate": DefaultRemarkTemplate,
  63. "subShowIdentityOnAllLinks": "false",
  64. "timeLocation": "Local",
  65. "tgBotEnable": "false",
  66. "tgBotToken": "",
  67. "tgBotProxy": "",
  68. "tgBotAPIServer": "",
  69. "tgBotChatId": "",
  70. "tgRunTime": "@daily",
  71. "tgBotBackup": "false",
  72. "tgCpu": "80",
  73. "tgMemory": "80",
  74. "tgLang": "en-US",
  75. "twoFactorEnable": "false",
  76. "twoFactorToken": "",
  77. "subEnable": "true",
  78. "subJsonEnable": "false",
  79. "subJsonAutoDetect": "false",
  80. "subJsonAlwaysArray": "false",
  81. "subJsonUserAgentRegex": "",
  82. "subClashAutoDetect": "false",
  83. "subClashUserAgentRegex": "",
  84. "subTitle": "",
  85. "subSupportUrl": "",
  86. "subProfileUrl": "",
  87. "subAnnounce": "",
  88. "subEnableRouting": "false",
  89. "subRoutingRules": "",
  90. "subHideSettings": "false",
  91. "subIncyEnableRouting": "false",
  92. "subIncyRoutingRules": "",
  93. "subListen": "",
  94. "subPort": "2096",
  95. "subPath": "/sub/",
  96. "subDomain": "",
  97. "subCertFile": "",
  98. "subKeyFile": "",
  99. "subUpdates": "12",
  100. "subEncrypt": "true",
  101. "subURI": "",
  102. "subJsonPath": "/json/",
  103. "subJsonURI": "",
  104. "subClashEnable": "false",
  105. "subClashPath": "/clash/",
  106. "subClashURI": "",
  107. "subClashEnableRouting": "false",
  108. "subClashRules": "",
  109. "subJsonMux": "",
  110. "subJsonRules": "",
  111. "subJsonFinalMask": "",
  112. "subThemeDir": "",
  113. "datepicker": "gregorian",
  114. "warp": "",
  115. "warpUpdateInterval": "0",
  116. "nord": "",
  117. "externalTrafficInformEnable": "false",
  118. "externalTrafficInformURI": "",
  119. "restartXrayOnClientDisable": "true",
  120. "xrayOutboundTestUrl": "https://www.google.com/generate_204",
  121. "panelOutbound": "",
  122. "devChannelEnable": "false",
  123. // LDAP defaults
  124. "ldapEnable": "false",
  125. "ldapHost": "",
  126. "ldapPort": "389",
  127. "ldapUseTLS": "false",
  128. "ldapInsecureSkipVerify": "false",
  129. "ldapBindDN": "",
  130. "ldapPassword": "",
  131. "ldapBaseDN": "",
  132. "ldapUserFilter": "(objectClass=person)",
  133. "ldapUserAttr": "mail",
  134. "ldapVlessField": "vless_enabled",
  135. "ldapSyncCron": "@every 1m",
  136. "ldapFlagField": "",
  137. "ldapTruthyValues": "true,1,yes,on",
  138. "ldapInvertFlag": "false",
  139. "ldapInboundTags": "",
  140. "ldapAutoCreate": "false",
  141. "ldapAutoDelete": "false",
  142. "ldapDefaultTotalGB": "0",
  143. "ldapDefaultExpiryDays": "0",
  144. "ldapDefaultLimitIP": "0",
  145. // Event bus — per-subscriber event filtering (empty = all disabled)
  146. "tgEnabledEvents": "login.attempt,cpu.high",
  147. "smtpEnabledEvents": "login.attempt,cpu.high",
  148. "smtpCpu": "80",
  149. "smtpMemory": "80",
  150. // Consecutive failed observatory probes before an outbound.down event fires
  151. "outboundDownThreshold": "3",
  152. // Email (SMTP) notifications
  153. "smtpEnable": "false",
  154. "smtpHost": "",
  155. "smtpPort": "587",
  156. "smtpUsername": "",
  157. "smtpPassword": "",
  158. "smtpFrom": "",
  159. "smtpFromName": "",
  160. "smtpTo": "",
  161. "smtpEncryptionType": "starttls", // no, starttls, tls
  162. }
  163. // SettingService provides business logic for application settings management.
  164. // It handles configuration storage, retrieval, and validation for all system settings.
  165. type SettingService struct{}
  166. func (s *SettingService) GetDefaultJSONConfig() (any, error) {
  167. var jsonData any
  168. err := json.Unmarshal([]byte(xrayTemplateConfig), &jsonData)
  169. if err != nil {
  170. return nil, err
  171. }
  172. return jsonData, nil
  173. }
  174. func (s *SettingService) GetAllSetting() (*entity.AllSetting, error) {
  175. db := database.GetDB()
  176. settings := make([]*model.Setting, 0)
  177. err := db.Model(model.Setting{}).Not("key = ?", "xrayTemplateConfig").Find(&settings).Error
  178. if err != nil {
  179. return nil, err
  180. }
  181. allSetting := &entity.AllSetting{}
  182. t := reflect.TypeFor[entity.AllSetting]()
  183. v := reflect.ValueOf(allSetting).Elem()
  184. fields := reflect_util.GetFields(t)
  185. setSetting := func(key, value string) (err error) {
  186. defer func() {
  187. panicErr := recover()
  188. if panicErr != nil {
  189. err = errors.New(fmt.Sprint(panicErr))
  190. }
  191. }()
  192. var found bool
  193. var field reflect.StructField
  194. for _, f := range fields {
  195. if f.Tag.Get("json") == key {
  196. field = f
  197. found = true
  198. break
  199. }
  200. }
  201. if !found {
  202. // Some settings are automatically generated, no need to return to the front end to modify the user
  203. return nil
  204. }
  205. fieldV := v.FieldByName(field.Name)
  206. switch t := fieldV.Interface().(type) {
  207. case int:
  208. n, err := strconv.ParseInt(effectiveSettingValue(key, value), 10, 64)
  209. if err != nil {
  210. return err
  211. }
  212. fieldV.SetInt(n)
  213. case string:
  214. fieldV.SetString(value)
  215. case bool:
  216. fieldV.SetBool(effectiveSettingValue(key, value) == "true")
  217. default:
  218. return common.NewErrorf("unknown field %v type %v", key, t)
  219. }
  220. return
  221. }
  222. keyMap := map[string]bool{}
  223. for _, setting := range settings {
  224. err := setSetting(setting.Key, setting.Value)
  225. if err != nil {
  226. return nil, err
  227. }
  228. keyMap[setting.Key] = true
  229. }
  230. for key, value := range defaultValueMap {
  231. if keyMap[key] {
  232. continue
  233. }
  234. err := setSetting(key, value)
  235. if err != nil {
  236. return nil, err
  237. }
  238. }
  239. return allSetting, nil
  240. }
  241. func (s *SettingService) GetAllSettingView() (*entity.AllSettingView, error) {
  242. allSetting, err := s.GetAllSetting()
  243. if err != nil {
  244. return nil, err
  245. }
  246. view := &entity.AllSettingView{AllSetting: *allSetting}
  247. view.HasTgBotToken = secretConfigured(allSetting.TgBotToken)
  248. view.HasTwoFactorToken = secretConfigured(allSetting.TwoFactorToken)
  249. view.HasLdapPassword = secretConfigured(allSetting.LdapPassword)
  250. view.HasWarpSecret = secretConfigured(mustString(s.GetWarp()))
  251. view.HasNordSecret = secretConfigured(mustString(s.GetNord()))
  252. view.HasSmtpPassword = secretConfigured(allSetting.SmtpPassword)
  253. var apiTokenCount int64
  254. if err := database.GetDB().Model(model.ApiToken{}).Where("enabled = ?", true).Count(&apiTokenCount).Error; err == nil {
  255. view.HasApiToken = apiTokenCount > 0
  256. }
  257. view.TgBotToken = ""
  258. view.TwoFactorToken = ""
  259. view.LdapPassword = ""
  260. view.SmtpPassword = ""
  261. return view, nil
  262. }
  263. func secretConfigured(value string) bool {
  264. return strings.TrimSpace(value) != ""
  265. }
  266. func mustString(value string, _ error) string {
  267. return value
  268. }
  269. func getEnv(key, fallback string) string {
  270. val, ok := os.LookupEnv(key)
  271. if !ok {
  272. return fallback
  273. }
  274. val = strings.TrimSpace(val)
  275. if val == "" {
  276. return fallback
  277. }
  278. return val
  279. }
  280. func (s *SettingService) ResetSettings() error {
  281. db := database.GetDB()
  282. err := db.Where("1 = 1").Delete(model.Setting{}).Error
  283. if err != nil {
  284. return err
  285. }
  286. return db.Model(model.User{}).
  287. Where("1 = 1").Error
  288. }
  289. func (s *SettingService) getSetting(key string) (*model.Setting, error) {
  290. db := database.GetDB()
  291. setting := &model.Setting{}
  292. err := db.Model(model.Setting{}).Where("key = ?", key).First(setting).Error
  293. if err != nil {
  294. return nil, err
  295. }
  296. return setting, nil
  297. }
  298. func (s *SettingService) saveSetting(key string, value string) error {
  299. setting, err := s.getSetting(key)
  300. db := database.GetDB()
  301. if database.IsNotFound(err) {
  302. return db.Create(&model.Setting{
  303. Key: key,
  304. Value: value,
  305. }).Error
  306. } else if err != nil {
  307. return err
  308. }
  309. setting.Key = key
  310. setting.Value = value
  311. return db.Save(setting).Error
  312. }
  313. func (s *SettingService) getString(key string) (string, error) {
  314. setting, err := s.getSetting(key)
  315. if database.IsNotFound(err) {
  316. value, ok := defaultValueMap[key]
  317. if !ok {
  318. return "", common.NewErrorf("key <%v> not in defaultValueMap", key)
  319. }
  320. return value, nil
  321. } else if err != nil {
  322. return "", err
  323. }
  324. return setting.Value, nil
  325. }
  326. func (s *SettingService) setString(key string, value string) error {
  327. return s.saveSetting(key, value)
  328. }
  329. func effectiveSettingValue(key, stored string) string {
  330. if stored == "" {
  331. if def, ok := defaultValueMap[key]; ok {
  332. return def
  333. }
  334. }
  335. return stored
  336. }
  337. func (s *SettingService) getBool(key string) (bool, error) {
  338. str, err := s.getString(key)
  339. if err != nil {
  340. return false, err
  341. }
  342. return strconv.ParseBool(effectiveSettingValue(key, str))
  343. }
  344. func (s *SettingService) setBool(key string, value bool) error {
  345. return s.setString(key, strconv.FormatBool(value))
  346. }
  347. func (s *SettingService) getInt(key string) (int, error) {
  348. str, err := s.getString(key)
  349. if err != nil {
  350. return 0, err
  351. }
  352. return strconv.Atoi(effectiveSettingValue(key, str))
  353. }
  354. func (s *SettingService) setInt(key string, value int) error {
  355. return s.setString(key, strconv.Itoa(value))
  356. }
  357. func (s *SettingService) GetWarpLastUpdate() (int64, error) {
  358. val, err := s.getString("warpLastUpdate")
  359. if err != nil || val == "" {
  360. return 0, err
  361. }
  362. return strconv.ParseInt(val, 10, 64)
  363. }
  364. func (s *SettingService) SetWarpLastUpdate(val int64) error {
  365. return s.saveSetting("warpLastUpdate", strconv.FormatInt(val, 10))
  366. }
  367. func (s *SettingService) SetWarpUpdateInterval(val int) error {
  368. return s.setInt("warpUpdateInterval", val)
  369. }
  370. func (s *SettingService) GetXrayConfigTemplate() (string, error) {
  371. return s.getString("xrayTemplateConfig")
  372. }
  373. func (s *SettingService) GetXrayOutboundTestUrl() (string, error) {
  374. return s.getString("xrayOutboundTestUrl")
  375. }
  376. func (s *SettingService) SetXrayOutboundTestUrl(url string) error {
  377. clean, err := SanitizeHTTPURL(url)
  378. if err != nil {
  379. return err
  380. }
  381. return s.setString("xrayOutboundTestUrl", clean)
  382. }
  383. func (s *SettingService) GetListen() (string, error) {
  384. return s.getString("webListen")
  385. }
  386. func (s *SettingService) SetListen(ip string) error {
  387. return s.setString("webListen", ip)
  388. }
  389. func (s *SettingService) GetWebDomain() (string, error) {
  390. return s.getString("webDomain")
  391. }
  392. func (s *SettingService) GetTgBotToken() (string, error) {
  393. return s.getString("tgBotToken")
  394. }
  395. func (s *SettingService) SetTgBotToken(token string) error {
  396. return s.setString("tgBotToken", token)
  397. }
  398. func (s *SettingService) GetTgBotProxy() (string, error) {
  399. return s.getString("tgBotProxy")
  400. }
  401. func (s *SettingService) SetTgBotProxy(token string) error {
  402. return s.setString("tgBotProxy", token)
  403. }
  404. // GetPanelOutbound returns the Xray outbound tag the panel's own outbound
  405. // requests (version checks, Telegram, subscription fetches) are routed through.
  406. func (s *SettingService) GetPanelOutbound() (string, error) {
  407. return s.getString("panelOutbound")
  408. }
  409. func (s *SettingService) SetPanelOutbound(tag string) error {
  410. return s.setString("panelOutbound", tag)
  411. }
  412. // PanelEgressProxyURL resolves the loopback SOCKS bridge that the generated
  413. // config exposes when a panel outbound is configured (see injectPanelEgress).
  414. // It returns "" — meaning a direct connection — when the feature is off or
  415. // the bridge is not present in the running core yet.
  416. func (s *SettingService) PanelEgressProxyURL() string {
  417. tag, err := s.GetPanelOutbound()
  418. if err != nil || tag == "" {
  419. return ""
  420. }
  421. proc := XrayProcess()
  422. if proc == nil || !proc.IsRunning() {
  423. logger.Warning("panel outbound [", tag, "] is set but Xray is not running, using a direct connection")
  424. return ""
  425. }
  426. cfg := proc.GetConfig()
  427. if cfg == nil {
  428. return ""
  429. }
  430. for i := range cfg.InboundConfigs {
  431. if cfg.InboundConfigs[i].Tag == PanelEgressInboundTag {
  432. return fmt.Sprintf("socks5://127.0.0.1:%d", cfg.InboundConfigs[i].Port)
  433. }
  434. }
  435. logger.Warning("panel outbound [", tag, "] is set but the egress bridge is not in the running config, using a direct connection")
  436. return ""
  437. }
  438. func (s *SettingService) NodeEgressProxyURL(nodeID int) string {
  439. tag := NodeEgressInboundTag(nodeID)
  440. proc := XrayProcess()
  441. if proc == nil || !proc.IsRunning() {
  442. logger.Warning("node outbound [", tag, "] is set but Xray is not running, using a direct connection")
  443. return ""
  444. }
  445. cfg := proc.GetConfig()
  446. if cfg == nil {
  447. return ""
  448. }
  449. for i := range cfg.InboundConfigs {
  450. if cfg.InboundConfigs[i].Tag == tag {
  451. return fmt.Sprintf("socks5://127.0.0.1:%d", cfg.InboundConfigs[i].Port)
  452. }
  453. }
  454. logger.Warning("node outbound [", tag, "] is set but the egress bridge is not in the running config, using a direct connection")
  455. return ""
  456. }
  457. // NewProxiedHTTPClient returns an HTTP client that routes the panel's own
  458. // outbound requests through the configured panel outbound (via the loopback
  459. // SOCKS bridge in the running Xray). When the feature is off or the bridge
  460. // is unavailable it falls back to a direct client.
  461. func (s *SettingService) NewProxiedHTTPClient(timeout time.Duration) *http.Client {
  462. proxyUrl := s.PanelEgressProxyURL()
  463. client, err := netproxy.NewHTTPClient(proxyUrl, timeout)
  464. if err != nil {
  465. logger.Warningf("Invalid panel egress proxy %q, using direct connection: %v", proxyUrl, err)
  466. return &http.Client{Timeout: timeout}
  467. }
  468. return client
  469. }
  470. func (s *SettingService) GetTgBotAPIServer() (string, error) {
  471. return s.getString("tgBotAPIServer")
  472. }
  473. func (s *SettingService) SetTgBotAPIServer(token string) error {
  474. return s.setString("tgBotAPIServer", token)
  475. }
  476. func (s *SettingService) GetTgBotChatId() (string, error) {
  477. return s.getString("tgBotChatId")
  478. }
  479. func (s *SettingService) SetTgBotChatId(chatIds string) error {
  480. return s.setString("tgBotChatId", chatIds)
  481. }
  482. func (s *SettingService) GetTgbotEnabled() (bool, error) {
  483. return s.getBool("tgBotEnable")
  484. }
  485. func (s *SettingService) SetTgbotEnabled(value bool) error {
  486. return s.setBool("tgBotEnable", value)
  487. }
  488. func (s *SettingService) GetTgbotRuntime() (string, error) {
  489. return s.getString("tgRunTime")
  490. }
  491. func (s *SettingService) SetTgbotRuntime(time string) error {
  492. return s.setString("tgRunTime", time)
  493. }
  494. func (s *SettingService) GetTgBotBackup() (bool, error) {
  495. return s.getBool("tgBotBackup")
  496. }
  497. func (s *SettingService) GetTgCpu() (int, error) {
  498. return s.getInt("tgCpu")
  499. }
  500. func (s *SettingService) GetTgMemory() (int, error) {
  501. return s.getInt("tgMemory")
  502. }
  503. func (s *SettingService) SetTgMemory(value int) error {
  504. return s.setInt("tgMemory", value)
  505. }
  506. func (s *SettingService) GetTgLang() (string, error) {
  507. return s.getString("tgLang")
  508. }
  509. func (s *SettingService) GetTwoFactorEnable() (bool, error) {
  510. return s.getBool("twoFactorEnable")
  511. }
  512. func (s *SettingService) SetTwoFactorEnable(value bool) error {
  513. return s.setBool("twoFactorEnable", value)
  514. }
  515. func (s *SettingService) GetTwoFactorToken() (string, error) {
  516. return s.getString("twoFactorToken")
  517. }
  518. func (s *SettingService) SetTwoFactorToken(value string) error {
  519. return s.setString("twoFactorToken", value)
  520. }
  521. func (s *SettingService) VerifyTwoFactorCode(code string) error {
  522. enabled, err := s.GetTwoFactorEnable()
  523. if err != nil {
  524. return err
  525. }
  526. if !enabled {
  527. return nil
  528. }
  529. token, err := s.GetTwoFactorToken()
  530. if err != nil {
  531. return err
  532. }
  533. if strings.TrimSpace(token) == "" || !gotp.NewDefaultTOTP(token).Verify(strings.TrimSpace(code), time.Now().Unix()) {
  534. return common.NewError("invalid two factor code")
  535. }
  536. return nil
  537. }
  538. func (s *SettingService) GetPort() (int, error) {
  539. return s.getInt("webPort")
  540. }
  541. func (s *SettingService) SetPort(port int) error {
  542. return s.setInt("webPort", port)
  543. }
  544. func (s *SettingService) SetCertFile(webCertFile string) error {
  545. return s.setString("webCertFile", webCertFile)
  546. }
  547. func (s *SettingService) GetCertFile() (string, error) {
  548. return s.getString("webCertFile")
  549. }
  550. func (s *SettingService) SetKeyFile(webKeyFile string) error {
  551. return s.setString("webKeyFile", webKeyFile)
  552. }
  553. func (s *SettingService) GetKeyFile() (string, error) {
  554. return s.getString("webKeyFile")
  555. }
  556. func (s *SettingService) GetExpireDiff() (int, error) {
  557. return s.getInt("expireDiff")
  558. }
  559. func (s *SettingService) GetTrafficDiff() (int, error) {
  560. return s.getInt("trafficDiff")
  561. }
  562. func (s *SettingService) GetSessionMaxAge() (int, error) {
  563. return s.getInt("sessionMaxAge")
  564. }
  565. func (s *SettingService) GetTrustedProxyCIDRs() (string, error) {
  566. return s.getString("trustedProxyCIDRs")
  567. }
  568. func (s *SettingService) GetRemarkTemplate() (string, error) {
  569. return s.getString("remarkTemplate")
  570. }
  571. func (s *SettingService) GetSubShowIdentityOnAllLinks() (bool, error) {
  572. return s.getBool("subShowIdentityOnAllLinks")
  573. }
  574. func (s *SettingService) GetSecret() ([]byte, error) {
  575. secret, err := s.getString("secret")
  576. if secret == defaultValueMap["secret"] {
  577. err := s.saveSetting("secret", secret)
  578. if err != nil {
  579. logger.Warning("save secret failed:", err)
  580. }
  581. }
  582. return []byte(secret), err
  583. }
  584. // GetPanelGuid returns this panel's stable self-identifier, persisting a
  585. // freshly generated UUID on first read. It is the globally stable node
  586. // identity used to attribute online clients and inbounds to the physical
  587. // node that hosts them across a chain of nodes (#4983), where per-panel
  588. // autoincrement node ids are meaningless one hop away.
  589. func (s *SettingService) GetPanelGuid() (string, error) {
  590. guid, err := s.getString("panelGuid")
  591. if err != nil {
  592. return "", err
  593. }
  594. if guid == defaultValueMap["panelGuid"] {
  595. if saveErr := s.saveSetting("panelGuid", guid); saveErr != nil {
  596. logger.Warning("save panelGuid failed:", saveErr)
  597. }
  598. }
  599. return guid, nil
  600. }
  601. func (s *SettingService) SetBasePath(basePath string) error {
  602. if !strings.HasPrefix(basePath, "/") {
  603. basePath = "/" + basePath
  604. }
  605. if !strings.HasSuffix(basePath, "/") {
  606. basePath += "/"
  607. }
  608. return s.setString("webBasePath", basePath)
  609. }
  610. func (s *SettingService) GetBasePath() (string, error) {
  611. basePath, err := s.getString("webBasePath")
  612. if err != nil {
  613. return "", err
  614. }
  615. return normalizeBasePath(basePath), nil
  616. }
  617. func (s *SettingService) GetTimeLocation() (*time.Location, error) {
  618. l, err := s.getString("timeLocation")
  619. if err != nil {
  620. return nil, err
  621. }
  622. location, err := time.LoadLocation(l)
  623. if err != nil {
  624. defaultLocation := defaultValueMap["timeLocation"]
  625. logger.Errorf("location <%v> not exist, using default location: %v", l, defaultLocation)
  626. location, err = time.LoadLocation(defaultLocation)
  627. if err != nil {
  628. logger.Errorf("failed to load default location, using UTC: %v", err)
  629. return time.UTC, nil
  630. }
  631. return location, nil
  632. }
  633. return location, nil
  634. }
  635. func (s *SettingService) GetSubEnable() (bool, error) {
  636. return s.getBool("subEnable")
  637. }
  638. func (s *SettingService) GetSubJsonEnable() (bool, error) {
  639. return s.getBool("subJsonEnable")
  640. }
  641. func (s *SettingService) GetSubJsonAutoDetect() (bool, error) {
  642. return s.getBool("subJsonAutoDetect")
  643. }
  644. func (s *SettingService) GetSubJsonAlwaysArray() (bool, error) {
  645. return s.getBool("subJsonAlwaysArray")
  646. }
  647. func (s *SettingService) GetSubJsonUserAgentRegex() (string, error) {
  648. return s.getString("subJsonUserAgentRegex")
  649. }
  650. func (s *SettingService) GetSubClashAutoDetect() (bool, error) {
  651. return s.getBool("subClashAutoDetect")
  652. }
  653. func (s *SettingService) GetSubClashUserAgentRegex() (string, error) {
  654. return s.getString("subClashUserAgentRegex")
  655. }
  656. func (s *SettingService) GetSubTitle() (string, error) {
  657. return s.getString("subTitle")
  658. }
  659. func (s *SettingService) GetSubSupportUrl() (string, error) {
  660. value, err := s.getString("subSupportUrl")
  661. return common.EnsureURLScheme(value), err
  662. }
  663. func (s *SettingService) GetSubProfileUrl() (string, error) {
  664. value, err := s.getString("subProfileUrl")
  665. return common.EnsureURLScheme(value), err
  666. }
  667. func (s *SettingService) GetSubAnnounce() (string, error) {
  668. return s.getString("subAnnounce")
  669. }
  670. func (s *SettingService) GetSubEnableRouting() (bool, error) {
  671. return s.getBool("subEnableRouting")
  672. }
  673. func (s *SettingService) GetSubRoutingRules() (string, error) {
  674. return s.getString("subRoutingRules")
  675. }
  676. func (s *SettingService) GetSubHideSettings() (bool, error) {
  677. return s.getBool("subHideSettings")
  678. }
  679. func (s *SettingService) GetSubIncyEnableRouting() (bool, error) {
  680. return s.getBool("subIncyEnableRouting")
  681. }
  682. func (s *SettingService) GetSubIncyRoutingRules() (string, error) {
  683. return s.getString("subIncyRoutingRules")
  684. }
  685. func (s *SettingService) GetSubListen() (string, error) {
  686. return s.getString("subListen")
  687. }
  688. func (s *SettingService) GetSubPort() (int, error) {
  689. return s.getInt("subPort")
  690. }
  691. func (s *SettingService) GetSubPath() (string, error) {
  692. return s.getString("subPath")
  693. }
  694. func (s *SettingService) GetSubJsonPath() (string, error) {
  695. return s.getString("subJsonPath")
  696. }
  697. func (s *SettingService) GetSubDomain() (string, error) {
  698. return s.getString("subDomain")
  699. }
  700. func (s *SettingService) SetSubCertFile(subCertFile string) error {
  701. return s.setString("subCertFile", subCertFile)
  702. }
  703. func (s *SettingService) GetSubCertFile() (string, error) {
  704. return s.getString("subCertFile")
  705. }
  706. func (s *SettingService) SetSubKeyFile(subKeyFile string) error {
  707. return s.setString("subKeyFile", subKeyFile)
  708. }
  709. func (s *SettingService) GetSubKeyFile() (string, error) {
  710. return s.getString("subKeyFile")
  711. }
  712. func (s *SettingService) GetSubUpdates() (string, error) {
  713. return s.getString("subUpdates")
  714. }
  715. func (s *SettingService) GetSubEncrypt() (bool, error) {
  716. return s.getBool("subEncrypt")
  717. }
  718. func (s *SettingService) GetPageSize() (int, error) {
  719. return s.getInt("pageSize")
  720. }
  721. func (s *SettingService) GetSubURI() (string, error) {
  722. return s.getString("subURI")
  723. }
  724. func (s *SettingService) GetSubJsonURI() (string, error) {
  725. return s.getString("subJsonURI")
  726. }
  727. func (s *SettingService) GetSubClashEnable() (bool, error) {
  728. return s.getBool("subClashEnable")
  729. }
  730. func (s *SettingService) GetSubClashPath() (string, error) {
  731. return s.getString("subClashPath")
  732. }
  733. func (s *SettingService) GetSubClashURI() (string, error) {
  734. return s.getString("subClashURI")
  735. }
  736. func (s *SettingService) GetSubClashEnableRouting() (bool, error) {
  737. return s.getBool("subClashEnableRouting")
  738. }
  739. func (s *SettingService) GetSubClashRules() (string, error) {
  740. return s.getString("subClashRules")
  741. }
  742. func (s *SettingService) GetSubJsonMux() (string, error) {
  743. return s.getString("subJsonMux")
  744. }
  745. func (s *SettingService) GetSubJsonRules() (string, error) {
  746. return s.getString("subJsonRules")
  747. }
  748. func (s *SettingService) GetSubJsonFinalMask() (string, error) {
  749. return s.getString("subJsonFinalMask")
  750. }
  751. func (s *SettingService) GetSubThemeDir() (string, error) {
  752. return s.getString("subThemeDir")
  753. }
  754. func (s *SettingService) GetDatepicker() (string, error) {
  755. return s.getString("datepicker")
  756. }
  757. func (s *SettingService) GetWarp() (string, error) {
  758. return s.getString("warp")
  759. }
  760. func (s *SettingService) SetWarp(data string) error {
  761. return s.setString("warp", data)
  762. }
  763. func (s *SettingService) GetNord() (string, error) {
  764. return s.getString("nord")
  765. }
  766. func (s *SettingService) SetNord(data string) error {
  767. return s.setString("nord", data)
  768. }
  769. func (s *SettingService) GetExternalTrafficInformEnable() (bool, error) {
  770. return s.getBool("externalTrafficInformEnable")
  771. }
  772. func (s *SettingService) SetExternalTrafficInformEnable(value bool) error {
  773. return s.setBool("externalTrafficInformEnable", value)
  774. }
  775. func (s *SettingService) GetExternalTrafficInformURI() (string, error) {
  776. return s.getString("externalTrafficInformURI")
  777. }
  778. func (s *SettingService) SetExternalTrafficInformURI(InformURI string) error {
  779. return s.setString("externalTrafficInformURI", InformURI)
  780. }
  781. func (s *SettingService) GetRestartXrayOnClientDisable() (bool, error) {
  782. return s.getBool("restartXrayOnClientDisable")
  783. }
  784. func (s *SettingService) SetRestartXrayOnClientDisable(value bool) error {
  785. return s.setBool("restartXrayOnClientDisable", value)
  786. }
  787. // GetDevChannelEnable reports whether the panel self-update tracks the rolling
  788. // per-commit dev release instead of the latest stable tag.
  789. func (s *SettingService) GetDevChannelEnable() (bool, error) {
  790. return s.getBool("devChannelEnable")
  791. }
  792. func (s *SettingService) SetDevChannelEnable(value bool) error {
  793. return s.setBool("devChannelEnable", value)
  794. }
  795. // GetIpLimitEnable reports whether the IP-limit feature is available. Always
  796. // true since the panel enforces limits via the core's online-stats API; on an
  797. // older core the job falls back to access-log parsing and warns there when the
  798. // log is missing, so the UI no longer hides the field behind that condition.
  799. func (s *SettingService) GetIpLimitEnable() (bool, error) {
  800. return true, nil
  801. }
  802. // GetAccessLogEnable reports whether an Xray access log is configured. Used by
  803. // the UI for features that genuinely read the log file (the xray log viewer) —
  804. // distinct from IP limiting, which works without it.
  805. func (s *SettingService) GetAccessLogEnable() (bool, error) {
  806. accessLogPath, err := xray.GetAccessLogPath()
  807. if err != nil {
  808. return false, err
  809. }
  810. return (accessLogPath != "none" && accessLogPath != ""), nil
  811. }
  812. // GetLdapEnable returns whether LDAP is enabled.
  813. func (s *SettingService) GetLdapEnable() (bool, error) {
  814. return s.getBool("ldapEnable")
  815. }
  816. func (s *SettingService) GetLdapHost() (string, error) {
  817. return s.getString("ldapHost")
  818. }
  819. func (s *SettingService) GetLdapPort() (int, error) {
  820. return s.getInt("ldapPort")
  821. }
  822. func (s *SettingService) GetLdapUseTLS() (bool, error) {
  823. return s.getBool("ldapUseTLS")
  824. }
  825. func (s *SettingService) GetLdapInsecureSkipVerify() (bool, error) {
  826. return s.getBool("ldapInsecureSkipVerify")
  827. }
  828. func (s *SettingService) GetLdapBindDN() (string, error) {
  829. return s.getString("ldapBindDN")
  830. }
  831. func (s *SettingService) GetLdapPassword() (string, error) {
  832. return s.getString("ldapPassword")
  833. }
  834. func (s *SettingService) GetLdapBaseDN() (string, error) {
  835. return s.getString("ldapBaseDN")
  836. }
  837. func (s *SettingService) GetLdapUserFilter() (string, error) {
  838. return s.getString("ldapUserFilter")
  839. }
  840. func (s *SettingService) GetLdapUserAttr() (string, error) {
  841. return s.getString("ldapUserAttr")
  842. }
  843. func (s *SettingService) GetLdapVlessField() (string, error) {
  844. return s.getString("ldapVlessField")
  845. }
  846. func (s *SettingService) GetLdapSyncCron() (string, error) {
  847. return s.getString("ldapSyncCron")
  848. }
  849. func (s *SettingService) GetLdapFlagField() (string, error) {
  850. return s.getString("ldapFlagField")
  851. }
  852. func (s *SettingService) GetLdapTruthyValues() (string, error) {
  853. return s.getString("ldapTruthyValues")
  854. }
  855. func (s *SettingService) GetLdapInvertFlag() (bool, error) {
  856. return s.getBool("ldapInvertFlag")
  857. }
  858. func (s *SettingService) GetLdapInboundTags() (string, error) {
  859. return s.getString("ldapInboundTags")
  860. }
  861. func (s *SettingService) GetLdapAutoCreate() (bool, error) {
  862. return s.getBool("ldapAutoCreate")
  863. }
  864. func (s *SettingService) GetLdapAutoDelete() (bool, error) {
  865. return s.getBool("ldapAutoDelete")
  866. }
  867. func (s *SettingService) GetLdapDefaultTotalGB() (int, error) {
  868. return s.getInt("ldapDefaultTotalGB")
  869. }
  870. func (s *SettingService) GetLdapDefaultExpiryDays() (int, error) {
  871. return s.getInt("ldapDefaultExpiryDays")
  872. }
  873. func (s *SettingService) GetLdapDefaultLimitIP() (int, error) {
  874. return s.getInt("ldapDefaultLimitIP")
  875. }
  876. // Event bus — per-subscriber event filtering
  877. func (s *SettingService) GetTgEnabledEvents() (string, error) {
  878. return s.getString("tgEnabledEvents")
  879. }
  880. func (s *SettingService) SetTgEnabledEvents(events string) error {
  881. return s.setString("tgEnabledEvents", events)
  882. }
  883. func (s *SettingService) GetSmtpEnabledEvents() (string, error) {
  884. return s.getString("smtpEnabledEvents")
  885. }
  886. func (s *SettingService) SetSmtpEnabledEvents(events string) error {
  887. return s.setString("smtpEnabledEvents", events)
  888. }
  889. // Email (SMTP) settings
  890. func (s *SettingService) GetSmtpEnable() (bool, error) {
  891. return s.getBool("smtpEnable")
  892. }
  893. func (s *SettingService) SetSmtpEnable(value bool) error {
  894. return s.setBool("smtpEnable", value)
  895. }
  896. func (s *SettingService) GetSmtpHost() (string, error) {
  897. return s.getString("smtpHost")
  898. }
  899. func (s *SettingService) SetSmtpHost(value string) error {
  900. return s.setString("smtpHost", value)
  901. }
  902. func (s *SettingService) GetSmtpPort() (int, error) {
  903. return s.getInt("smtpPort")
  904. }
  905. func (s *SettingService) SetSmtpPort(value int) error {
  906. return s.setInt("smtpPort", value)
  907. }
  908. func (s *SettingService) GetSmtpUsername() (string, error) {
  909. return s.getString("smtpUsername")
  910. }
  911. func (s *SettingService) SetSmtpUsername(value string) error {
  912. return s.setString("smtpUsername", value)
  913. }
  914. func (s *SettingService) GetSmtpFrom() (string, error) {
  915. return s.getString("smtpFrom")
  916. }
  917. func (s *SettingService) SetSmtpFrom(value string) error {
  918. return s.setString("smtpFrom", value)
  919. }
  920. func (s *SettingService) GetSmtpFromName() (string, error) {
  921. return s.getString("smtpFromName")
  922. }
  923. func (s *SettingService) SetSmtpFromName(value string) error {
  924. return s.setString("smtpFromName", value)
  925. }
  926. func (s *SettingService) GetSmtpPassword() (string, error) {
  927. return s.getString("smtpPassword")
  928. }
  929. func (s *SettingService) SetSmtpPassword(value string) error {
  930. return s.setString("smtpPassword", value)
  931. }
  932. func (s *SettingService) GetSmtpTo() (string, error) {
  933. return s.getString("smtpTo")
  934. }
  935. func (s *SettingService) SetSmtpTo(value string) error {
  936. return s.setString("smtpTo", value)
  937. }
  938. func (s *SettingService) GetSmtpEncryptionType() (string, error) {
  939. return s.getString("smtpEncryptionType")
  940. }
  941. func (s *SettingService) SetSmtpEncryptionType(value string) error {
  942. return s.setString("smtpEncryptionType", value)
  943. }
  944. func (s *SettingService) GetSmtpCpu() (int, error) {
  945. return s.getInt("smtpCpu")
  946. }
  947. func (s *SettingService) SetSmtpCpu(value int) error {
  948. return s.setInt("smtpCpu", value)
  949. }
  950. func (s *SettingService) GetSmtpMemory() (int, error) {
  951. return s.getInt("smtpMemory")
  952. }
  953. func (s *SettingService) SetSmtpMemory(value int) error {
  954. return s.setInt("smtpMemory", value)
  955. }
  956. // GetOutboundDownThreshold returns how many consecutive failed observatory
  957. // probes an outbound must accumulate before an outbound.down notification is
  958. // emitted. 1 preserves the legacy "notify on the first failed probe" behaviour.
  959. func (s *SettingService) GetOutboundDownThreshold() (int, error) {
  960. return s.getInt("outboundDownThreshold")
  961. }
  962. func (s *SettingService) SetOutboundDownThreshold(value int) error {
  963. return s.setInt("outboundDownThreshold", value)
  964. }
  965. // SecretClears marks redacted secrets the user explicitly emptied. Without a
  966. // flag, a blank submitted secret means "unchanged" (the field is always served
  967. // blank to the browser) and the stored value is preserved.
  968. type SecretClears struct {
  969. TgBotToken bool
  970. LdapPassword bool
  971. SmtpPassword bool
  972. }
  973. func (s *SettingService) UpdateAllSetting(allSetting *entity.AllSetting, clears SecretClears) error {
  974. if err := s.preserveRedactedSecrets(allSetting, clears); err != nil {
  975. return err
  976. }
  977. if err := validateSettingsURLs(allSetting); err != nil {
  978. return err
  979. }
  980. if err := validateSubUserAgentRegexes(allSetting); err != nil {
  981. return err
  982. }
  983. if err := allSetting.CheckValid(); err != nil {
  984. return err
  985. }
  986. v := reflect.ValueOf(allSetting).Elem()
  987. t := reflect.TypeFor[entity.AllSetting]()
  988. fields := reflect_util.GetFields(t)
  989. db := database.GetDB()
  990. return db.Transaction(func(tx *gorm.DB) error {
  991. var existing []*model.Setting
  992. if err := tx.Find(&existing).Error; err != nil {
  993. return err
  994. }
  995. byKey := make(map[string]*model.Setting, len(existing))
  996. for _, st := range existing {
  997. byKey[st.Key] = st
  998. }
  999. for _, field := range fields {
  1000. key := field.Tag.Get("json")
  1001. fieldV := v.FieldByName(field.Name)
  1002. value := fmt.Sprint(fieldV.Interface())
  1003. if st, ok := byKey[key]; ok {
  1004. if st.Value == value {
  1005. continue
  1006. }
  1007. st.Value = value
  1008. if err := tx.Save(st).Error; err != nil {
  1009. return err
  1010. }
  1011. continue
  1012. }
  1013. if err := tx.Create(&model.Setting{Key: key, Value: value}).Error; err != nil {
  1014. return err
  1015. }
  1016. }
  1017. return nil
  1018. })
  1019. }
  1020. func validateSubUserAgentRegexes(allSetting *entity.AllSetting) error {
  1021. jsonPattern, err := validateSubUserAgentRegex("Xray JSON", allSetting.SubJsonUserAgentRegex, DefaultSubJsonUserAgentRegex)
  1022. if err != nil {
  1023. return err
  1024. }
  1025. clashPattern, err := validateSubUserAgentRegex("Clash/Mihomo", allSetting.SubClashUserAgentRegex, DefaultSubClashUserAgentRegex)
  1026. if err != nil {
  1027. return err
  1028. }
  1029. allSetting.SubJsonUserAgentRegex = jsonPattern
  1030. allSetting.SubClashUserAgentRegex = clashPattern
  1031. return nil
  1032. }
  1033. func validateSubUserAgentRegex(name, pattern, defaultPattern string) (string, error) {
  1034. pattern = strings.TrimSpace(pattern)
  1035. effectivePattern := pattern
  1036. if effectivePattern == "" {
  1037. effectivePattern = defaultPattern
  1038. }
  1039. if len(effectivePattern) > maxRegexLength {
  1040. return "", common.NewErrorf("%s User-Agent regex must not exceed %d characters", name, maxRegexLength)
  1041. }
  1042. if _, err := regexp.Compile(effectivePattern); err != nil {
  1043. return "", common.NewErrorf("%s User-Agent regex is invalid: %v", name, err)
  1044. }
  1045. // Return the original pattern (empty string if cleared) so the caller
  1046. // can distinguish "user explicitly set empty" from "user set a value".
  1047. // The empty value is stored in the DB and inherited as runtime default.
  1048. return pattern, nil
  1049. }
  1050. func ValidateRegex(pattern string) error {
  1051. if len(pattern) > maxRegexLength {
  1052. return common.NewErrorf("Regular expression must not exceed %d characters", maxRegexLength)
  1053. }
  1054. if _, err := regexp.Compile(pattern); err != nil {
  1055. return common.NewError("Regular expression is invalid:", err)
  1056. }
  1057. return nil
  1058. }
  1059. func (s *SettingService) preserveRedactedSecrets(allSetting *entity.AllSetting, clears SecretClears) error {
  1060. if !clears.TgBotToken && strings.TrimSpace(allSetting.TgBotToken) == "" {
  1061. value, err := s.GetTgBotToken()
  1062. if err != nil {
  1063. return err
  1064. }
  1065. allSetting.TgBotToken = value
  1066. }
  1067. if !clears.LdapPassword && strings.TrimSpace(allSetting.LdapPassword) == "" {
  1068. value, err := s.GetLdapPassword()
  1069. if err != nil {
  1070. return err
  1071. }
  1072. allSetting.LdapPassword = value
  1073. }
  1074. if allSetting.TwoFactorEnable && strings.TrimSpace(allSetting.TwoFactorToken) == "" {
  1075. value, err := s.GetTwoFactorToken()
  1076. if err != nil {
  1077. return err
  1078. }
  1079. allSetting.TwoFactorToken = value
  1080. }
  1081. if !clears.SmtpPassword && strings.TrimSpace(allSetting.SmtpPassword) == "" {
  1082. value, err := s.GetSmtpPassword()
  1083. if err != nil {
  1084. return err
  1085. }
  1086. allSetting.SmtpPassword = value
  1087. }
  1088. return nil
  1089. }
  1090. func validateSettingsURLs(allSetting *entity.AllSetting) error {
  1091. if allSetting.ExternalTrafficInformURI != "" {
  1092. u, err := SanitizeHTTPURL(allSetting.ExternalTrafficInformURI)
  1093. if err != nil {
  1094. return common.NewError("external traffic inform URI is invalid:", err)
  1095. }
  1096. allSetting.ExternalTrafficInformURI = u
  1097. }
  1098. if allSetting.TgBotAPIServer != "" {
  1099. u, err := SanitizeHTTPURL(allSetting.TgBotAPIServer)
  1100. if err != nil {
  1101. return common.NewError("telegram API server URL is invalid:", err)
  1102. }
  1103. allSetting.TgBotAPIServer = u
  1104. }
  1105. // Support/profile links land in subscription headers and page data, where
  1106. // client apps resolve a scheme-less value against the panel's own domain.
  1107. // Non-http schemes (tg://, mailto:) are legitimate here, so only default
  1108. // the scheme instead of forcing SanitizeHTTPURL's http(s)-only rule.
  1109. allSetting.SubSupportUrl = common.EnsureURLScheme(allSetting.SubSupportUrl)
  1110. allSetting.SubProfileUrl = common.EnsureURLScheme(allSetting.SubProfileUrl)
  1111. return nil
  1112. }
  1113. func (s *SettingService) UpdateSecret(key string, value string) error {
  1114. switch key {
  1115. case "tgBotToken", "ldapPassword", "twoFactorToken":
  1116. return s.saveSetting(key, strings.TrimSpace(value))
  1117. default:
  1118. return common.NewError("secret key is not replaceable:", key)
  1119. }
  1120. }
  1121. func (s *SettingService) GetDefaultXrayConfig() (any, error) {
  1122. var jsonData any
  1123. err := json.Unmarshal([]byte(xrayTemplateConfig), &jsonData)
  1124. if err != nil {
  1125. return nil, err
  1126. }
  1127. return jsonData, nil
  1128. }
  1129. func extractHostname(host string) string {
  1130. h, _, err := net.SplitHostPort(host)
  1131. // Err is not nil means host does not contain port
  1132. if err != nil {
  1133. h = host
  1134. }
  1135. ip := net.ParseIP(h)
  1136. // If it's not an IP, return as is
  1137. if ip == nil {
  1138. return h
  1139. }
  1140. // If it's an IPv4, return as is
  1141. if ip.To4() != nil {
  1142. return h
  1143. }
  1144. // IPv6 needs bracketing
  1145. return "[" + h + "]"
  1146. }
  1147. // BuildSubURIBase is shared by GetDefaultSettings (the panel's Client
  1148. // Information page) and the subscription page so both render subscription
  1149. // URLs identically.
  1150. func (s *SettingService) BuildSubURIBase(host string) string {
  1151. subPort, _ := s.GetSubPort()
  1152. subDomain, _ := s.GetSubDomain()
  1153. subKeyFile, _ := s.GetSubKeyFile()
  1154. subCertFile, _ := s.GetSubCertFile()
  1155. subTLS := subKeyFile != "" && subCertFile != ""
  1156. if subDomain == "" {
  1157. subDomain = extractHostname(host)
  1158. }
  1159. scheme := "http"
  1160. if subTLS {
  1161. scheme = "https"
  1162. }
  1163. if (subPort == 443 && subTLS) || (subPort == 80 && !subTLS) {
  1164. return scheme + "://" + subDomain
  1165. }
  1166. return fmt.Sprintf("%s://%s:%d", scheme, subDomain, subPort)
  1167. }
  1168. func (s *SettingService) GetDefaultSettings(host string) (any, error) {
  1169. type settingFunc func() (any, error)
  1170. settings := map[string]settingFunc{
  1171. "expireDiff": func() (any, error) { return s.GetExpireDiff() },
  1172. "trafficDiff": func() (any, error) { return s.GetTrafficDiff() },
  1173. "pageSize": func() (any, error) { return s.GetPageSize() },
  1174. "defaultCert": func() (any, error) { return s.GetCertFile() },
  1175. "defaultKey": func() (any, error) { return s.GetKeyFile() },
  1176. "tgBotEnable": func() (any, error) { return s.GetTgbotEnabled() },
  1177. "subThemeDir": func() (any, error) { return s.GetSubThemeDir() },
  1178. "subEnable": func() (any, error) { return s.GetSubEnable() },
  1179. "subJsonEnable": func() (any, error) { return s.GetSubJsonEnable() },
  1180. "subClashEnable": func() (any, error) { return s.GetSubClashEnable() },
  1181. "subTitle": func() (any, error) { return s.GetSubTitle() },
  1182. "subURI": func() (any, error) { return s.GetSubURI() },
  1183. "subJsonURI": func() (any, error) { return s.GetSubJsonURI() },
  1184. "subClashURI": func() (any, error) { return s.GetSubClashURI() },
  1185. "datepicker": func() (any, error) { return s.GetDatepicker() },
  1186. "ipLimitEnable": func() (any, error) { return s.GetIpLimitEnable() },
  1187. "accessLogEnable": func() (any, error) { return s.GetAccessLogEnable() },
  1188. "webDomain": func() (any, error) { return s.GetWebDomain() },
  1189. "subDomain": func() (any, error) { return s.GetSubDomain() },
  1190. "devChannelEnable": func() (any, error) { return s.GetDevChannelEnable() },
  1191. "isDevBuild": func() (any, error) { return config.IsDevBuild(), nil },
  1192. }
  1193. result := make(map[string]any)
  1194. for key, fn := range settings {
  1195. value, err := fn()
  1196. if err != nil {
  1197. return "", err
  1198. }
  1199. result[key] = value
  1200. }
  1201. subEnable := result["subEnable"].(bool)
  1202. subJsonEnable := false
  1203. if v, ok := result["subJsonEnable"]; ok {
  1204. if b, ok2 := v.(bool); ok2 {
  1205. subJsonEnable = b
  1206. }
  1207. }
  1208. subClashEnable := false
  1209. if v, ok := result["subClashEnable"]; ok {
  1210. if b, ok2 := v.(bool); ok2 {
  1211. subClashEnable = b
  1212. }
  1213. }
  1214. if (subEnable && result["subURI"].(string) == "") || (subJsonEnable && result["subJsonURI"].(string) == "") || (subClashEnable && result["subClashURI"].(string) == "") {
  1215. subURI := s.BuildSubURIBase(host)
  1216. subTitle, _ := s.GetSubTitle()
  1217. subPath, _ := s.GetSubPath()
  1218. subJsonPath, _ := s.GetSubJsonPath()
  1219. subClashPath, _ := s.GetSubClashPath()
  1220. if subEnable && result["subURI"].(string) == "" {
  1221. result["subURI"] = subURI + subPath
  1222. }
  1223. if result["subTitle"].(string) == "" {
  1224. result["subTitle"] = subTitle
  1225. }
  1226. if subJsonEnable && result["subJsonURI"].(string) == "" {
  1227. result["subJsonURI"] = subURI + subJsonPath
  1228. }
  1229. if subClashEnable && result["subClashURI"].(string) == "" {
  1230. result["subClashURI"] = subURI + subClashPath
  1231. }
  1232. }
  1233. return result, nil
  1234. }
  1235. var factoryDefaultSecretKeys = map[string]bool{
  1236. "tgBotToken": true,
  1237. "twoFactorToken": true,
  1238. "ldapPassword": true,
  1239. "smtpPassword": true,
  1240. }
  1241. /*
  1242. GetFactoryDefaults returns the shipped default value per setting, keyed by
  1243. the AllSetting json field name. Unlike GetDefaultSettings (which reports
  1244. current effective values), this is defaultValueMap projected through the
  1245. AllSetting field set: only keys that exist as an AllSetting json tag are
  1246. returned, minus the credential fields in factoryDefaultSecretKeys. Keys
  1247. with no AllSetting field (secret, panelGuid, the node mTLS material,
  1248. xrayTemplateConfig) are excluded structurally rather than by deny-list.
  1249. */
  1250. func (s *SettingService) GetFactoryDefaults() map[string]string {
  1251. result := make(map[string]string)
  1252. for _, field := range reflect_util.GetFields(reflect.TypeFor[entity.AllSetting]()) {
  1253. key := field.Tag.Get("json")
  1254. if key == "" || factoryDefaultSecretKeys[key] {
  1255. continue
  1256. }
  1257. if value, ok := defaultValueMap[key]; ok {
  1258. result[key] = value
  1259. }
  1260. }
  1261. return result
  1262. }