setting.go 48 KB

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