1
0

setting.go 59 KB

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