setting.go 44 KB

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