1
0

setting.go 42 KB

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