subService.go 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263
  1. package sub
  2. import (
  3. "encoding/base64"
  4. "fmt"
  5. "net"
  6. "net/url"
  7. "strings"
  8. "time"
  9. "github.com/gin-gonic/gin"
  10. "github.com/goccy/go-json"
  11. "github.com/mhsanaei/3x-ui/v2/database"
  12. "github.com/mhsanaei/3x-ui/v2/database/model"
  13. "github.com/mhsanaei/3x-ui/v2/logger"
  14. "github.com/mhsanaei/3x-ui/v2/util/common"
  15. "github.com/mhsanaei/3x-ui/v2/util/random"
  16. "github.com/mhsanaei/3x-ui/v2/web/service"
  17. "github.com/mhsanaei/3x-ui/v2/xray"
  18. )
  19. // SubService provides business logic for generating subscription links and managing subscription data.
  20. type SubService struct {
  21. address string
  22. showInfo bool
  23. remarkModel string
  24. datepicker string
  25. inboundService service.InboundService
  26. settingService service.SettingService
  27. }
  28. // NewSubService creates a new subscription service with the given configuration.
  29. func NewSubService(showInfo bool, remarkModel string) *SubService {
  30. return &SubService{
  31. showInfo: showInfo,
  32. remarkModel: remarkModel,
  33. }
  34. }
  35. // GetSubs retrieves subscription links for a given subscription ID and host.
  36. func (s *SubService) GetSubs(subId string, host string) ([]string, int64, xray.ClientTraffic, error) {
  37. s.address = host
  38. var result []string
  39. var traffic xray.ClientTraffic
  40. var lastOnline int64
  41. var clientTraffics []xray.ClientTraffic
  42. inbounds, err := s.getInboundsBySubId(subId)
  43. if err != nil {
  44. return nil, 0, traffic, err
  45. }
  46. if len(inbounds) == 0 {
  47. return nil, 0, traffic, common.NewError("No inbounds found with ", subId)
  48. }
  49. s.datepicker, err = s.settingService.GetDatepicker()
  50. if err != nil {
  51. s.datepicker = "gregorian"
  52. }
  53. for _, inbound := range inbounds {
  54. clients, err := s.inboundService.GetClients(inbound)
  55. if err != nil {
  56. logger.Error("SubService - GetClients: Unable to get clients from inbound")
  57. }
  58. if clients == nil {
  59. continue
  60. }
  61. if len(inbound.Listen) > 0 && inbound.Listen[0] == '@' {
  62. listen, port, streamSettings, err := s.getFallbackMaster(inbound.Listen, inbound.StreamSettings)
  63. if err == nil {
  64. inbound.Listen = listen
  65. inbound.Port = port
  66. inbound.StreamSettings = streamSettings
  67. }
  68. }
  69. for _, client := range clients {
  70. if client.Enable && client.SubID == subId {
  71. link := s.getLink(inbound, client.Email)
  72. result = append(result, link)
  73. ct := s.getClientTraffics(inbound.ClientStats, client.Email)
  74. clientTraffics = append(clientTraffics, ct)
  75. if ct.LastOnline > lastOnline {
  76. lastOnline = ct.LastOnline
  77. }
  78. }
  79. }
  80. }
  81. // Prepare statistics
  82. for index, clientTraffic := range clientTraffics {
  83. if index == 0 {
  84. traffic.Up = clientTraffic.Up
  85. traffic.Down = clientTraffic.Down
  86. traffic.Total = clientTraffic.Total
  87. if clientTraffic.ExpiryTime > 0 {
  88. traffic.ExpiryTime = clientTraffic.ExpiryTime
  89. }
  90. } else {
  91. traffic.Up += clientTraffic.Up
  92. traffic.Down += clientTraffic.Down
  93. if traffic.Total == 0 || clientTraffic.Total == 0 {
  94. traffic.Total = 0
  95. } else {
  96. traffic.Total += clientTraffic.Total
  97. }
  98. if clientTraffic.ExpiryTime != traffic.ExpiryTime {
  99. traffic.ExpiryTime = 0
  100. }
  101. }
  102. }
  103. return result, lastOnline, traffic, nil
  104. }
  105. func (s *SubService) getInboundsBySubId(subId string) ([]*model.Inbound, error) {
  106. db := database.GetDB()
  107. var inbounds []*model.Inbound
  108. err := db.Model(model.Inbound{}).Preload("ClientStats").Where(`id in (
  109. SELECT DISTINCT inbounds.id
  110. FROM inbounds,
  111. JSON_EACH(JSON_EXTRACT(inbounds.settings, '$.clients')) AS client
  112. WHERE
  113. protocol in ('vmess','vless','trojan','shadowsocks','hysteria')
  114. AND JSON_EXTRACT(client.value, '$.subId') = ? AND enable = ?
  115. )`, subId, true).Find(&inbounds).Error
  116. if err != nil {
  117. return nil, err
  118. }
  119. return inbounds, nil
  120. }
  121. func (s *SubService) getClientTraffics(traffics []xray.ClientTraffic, email string) xray.ClientTraffic {
  122. for _, traffic := range traffics {
  123. if traffic.Email == email {
  124. return traffic
  125. }
  126. }
  127. return xray.ClientTraffic{}
  128. }
  129. func (s *SubService) getFallbackMaster(dest string, streamSettings string) (string, int, string, error) {
  130. db := database.GetDB()
  131. var inbound *model.Inbound
  132. err := db.Model(model.Inbound{}).
  133. Where("JSON_TYPE(settings, '$.fallbacks') = 'array'").
  134. Where("EXISTS (SELECT * FROM json_each(settings, '$.fallbacks') WHERE json_extract(value, '$.dest') = ?)", dest).
  135. Find(&inbound).Error
  136. if err != nil {
  137. return "", 0, "", err
  138. }
  139. var stream map[string]any
  140. json.Unmarshal([]byte(streamSettings), &stream)
  141. var masterStream map[string]any
  142. json.Unmarshal([]byte(inbound.StreamSettings), &masterStream)
  143. stream["security"] = masterStream["security"]
  144. stream["tlsSettings"] = masterStream["tlsSettings"]
  145. stream["externalProxy"] = masterStream["externalProxy"]
  146. modifiedStream, _ := json.MarshalIndent(stream, "", " ")
  147. return inbound.Listen, inbound.Port, string(modifiedStream), nil
  148. }
  149. func (s *SubService) getLink(inbound *model.Inbound, email string) string {
  150. switch inbound.Protocol {
  151. case "vmess":
  152. return s.genVmessLink(inbound, email)
  153. case "vless":
  154. return s.genVlessLink(inbound, email)
  155. case "trojan":
  156. return s.genTrojanLink(inbound, email)
  157. case "shadowsocks":
  158. return s.genShadowsocksLink(inbound, email)
  159. case "hysteria":
  160. return s.genHysteriaLink(inbound, email)
  161. }
  162. return ""
  163. }
  164. func (s *SubService) genVmessLink(inbound *model.Inbound, email string) string {
  165. if inbound.Protocol != model.VMESS {
  166. return ""
  167. }
  168. var address string
  169. if inbound.Listen == "" || inbound.Listen == "0.0.0.0" || inbound.Listen == "::" || inbound.Listen == "::0" {
  170. address = s.address
  171. } else {
  172. address = inbound.Listen
  173. }
  174. obj := map[string]any{
  175. "v": "2",
  176. "add": address,
  177. "port": inbound.Port,
  178. "type": "none",
  179. }
  180. var stream map[string]any
  181. json.Unmarshal([]byte(inbound.StreamSettings), &stream)
  182. network, _ := stream["network"].(string)
  183. obj["net"] = network
  184. switch network {
  185. case "tcp":
  186. tcp, _ := stream["tcpSettings"].(map[string]any)
  187. header, _ := tcp["header"].(map[string]any)
  188. typeStr, _ := header["type"].(string)
  189. obj["type"] = typeStr
  190. if typeStr == "http" {
  191. request := header["request"].(map[string]any)
  192. requestPath, _ := request["path"].([]any)
  193. obj["path"] = requestPath[0].(string)
  194. headers, _ := request["headers"].(map[string]any)
  195. obj["host"] = searchHost(headers)
  196. }
  197. case "kcp":
  198. kcp, _ := stream["kcpSettings"].(map[string]any)
  199. header, _ := kcp["header"].(map[string]any)
  200. obj["type"], _ = header["type"].(string)
  201. obj["path"], _ = kcp["seed"].(string)
  202. case "ws":
  203. ws, _ := stream["wsSettings"].(map[string]any)
  204. obj["path"] = ws["path"].(string)
  205. if host, ok := ws["host"].(string); ok && len(host) > 0 {
  206. obj["host"] = host
  207. } else {
  208. headers, _ := ws["headers"].(map[string]any)
  209. obj["host"] = searchHost(headers)
  210. }
  211. case "grpc":
  212. grpc, _ := stream["grpcSettings"].(map[string]any)
  213. obj["path"] = grpc["serviceName"].(string)
  214. obj["authority"] = grpc["authority"].(string)
  215. if grpc["multiMode"].(bool) {
  216. obj["type"] = "multi"
  217. }
  218. case "httpupgrade":
  219. httpupgrade, _ := stream["httpupgradeSettings"].(map[string]any)
  220. obj["path"] = httpupgrade["path"].(string)
  221. if host, ok := httpupgrade["host"].(string); ok && len(host) > 0 {
  222. obj["host"] = host
  223. } else {
  224. headers, _ := httpupgrade["headers"].(map[string]any)
  225. obj["host"] = searchHost(headers)
  226. }
  227. case "xhttp":
  228. xhttp, _ := stream["xhttpSettings"].(map[string]any)
  229. obj["path"] = xhttp["path"].(string)
  230. if host, ok := xhttp["host"].(string); ok && len(host) > 0 {
  231. obj["host"] = host
  232. } else {
  233. headers, _ := xhttp["headers"].(map[string]any)
  234. obj["host"] = searchHost(headers)
  235. }
  236. obj["mode"], _ = xhttp["mode"].(string)
  237. }
  238. security, _ := stream["security"].(string)
  239. obj["tls"] = security
  240. if security == "tls" {
  241. tlsSetting, _ := stream["tlsSettings"].(map[string]any)
  242. alpns, _ := tlsSetting["alpn"].([]any)
  243. if len(alpns) > 0 {
  244. var alpn []string
  245. for _, a := range alpns {
  246. alpn = append(alpn, a.(string))
  247. }
  248. obj["alpn"] = strings.Join(alpn, ",")
  249. }
  250. if sniValue, ok := searchKey(tlsSetting, "serverName"); ok {
  251. obj["sni"], _ = sniValue.(string)
  252. }
  253. tlsSettings, _ := searchKey(tlsSetting, "settings")
  254. if tlsSetting != nil {
  255. if fpValue, ok := searchKey(tlsSettings, "fingerprint"); ok {
  256. obj["fp"], _ = fpValue.(string)
  257. }
  258. }
  259. }
  260. clients, _ := s.inboundService.GetClients(inbound)
  261. clientIndex := -1
  262. for i, client := range clients {
  263. if client.Email == email {
  264. clientIndex = i
  265. break
  266. }
  267. }
  268. obj["id"] = clients[clientIndex].ID
  269. obj["scy"] = clients[clientIndex].Security
  270. externalProxies, _ := stream["externalProxy"].([]any)
  271. if len(externalProxies) > 0 {
  272. links := ""
  273. for index, externalProxy := range externalProxies {
  274. ep, _ := externalProxy.(map[string]any)
  275. newSecurity, _ := ep["forceTls"].(string)
  276. newObj := map[string]any{}
  277. for key, value := range obj {
  278. if !(newSecurity == "none" && (key == "alpn" || key == "sni" || key == "fp")) {
  279. newObj[key] = value
  280. }
  281. }
  282. newObj["ps"] = s.genRemark(inbound, email, ep["remark"].(string))
  283. newObj["add"] = ep["dest"].(string)
  284. newObj["port"] = int(ep["port"].(float64))
  285. if newSecurity != "same" {
  286. newObj["tls"] = newSecurity
  287. }
  288. if index > 0 {
  289. links += "\n"
  290. }
  291. jsonStr, _ := json.MarshalIndent(newObj, "", " ")
  292. links += "vmess://" + base64.StdEncoding.EncodeToString(jsonStr)
  293. }
  294. return links
  295. }
  296. obj["ps"] = s.genRemark(inbound, email, "")
  297. jsonStr, _ := json.MarshalIndent(obj, "", " ")
  298. return "vmess://" + base64.StdEncoding.EncodeToString(jsonStr)
  299. }
  300. func (s *SubService) genVlessLink(inbound *model.Inbound, email string) string {
  301. var address string
  302. if inbound.Listen == "" || inbound.Listen == "0.0.0.0" || inbound.Listen == "::" || inbound.Listen == "::0" {
  303. address = s.address
  304. } else {
  305. address = inbound.Listen
  306. }
  307. if inbound.Protocol != model.VLESS {
  308. return ""
  309. }
  310. var stream map[string]any
  311. json.Unmarshal([]byte(inbound.StreamSettings), &stream)
  312. clients, _ := s.inboundService.GetClients(inbound)
  313. clientIndex := -1
  314. for i, client := range clients {
  315. if client.Email == email {
  316. clientIndex = i
  317. break
  318. }
  319. }
  320. uuid := clients[clientIndex].ID
  321. port := inbound.Port
  322. streamNetwork := stream["network"].(string)
  323. params := make(map[string]string)
  324. params["type"] = streamNetwork
  325. // Add encryption parameter for VLESS from inbound settings
  326. var settings map[string]any
  327. json.Unmarshal([]byte(inbound.Settings), &settings)
  328. if encryption, ok := settings["encryption"].(string); ok {
  329. params["encryption"] = encryption
  330. }
  331. switch streamNetwork {
  332. case "tcp":
  333. tcp, _ := stream["tcpSettings"].(map[string]any)
  334. header, _ := tcp["header"].(map[string]any)
  335. typeStr, _ := header["type"].(string)
  336. if typeStr == "http" {
  337. request := header["request"].(map[string]any)
  338. requestPath, _ := request["path"].([]any)
  339. params["path"] = requestPath[0].(string)
  340. headers, _ := request["headers"].(map[string]any)
  341. params["host"] = searchHost(headers)
  342. params["headerType"] = "http"
  343. }
  344. case "kcp":
  345. kcp, _ := stream["kcpSettings"].(map[string]any)
  346. header, _ := kcp["header"].(map[string]any)
  347. params["headerType"] = header["type"].(string)
  348. params["seed"] = kcp["seed"].(string)
  349. case "ws":
  350. ws, _ := stream["wsSettings"].(map[string]any)
  351. params["path"] = ws["path"].(string)
  352. if host, ok := ws["host"].(string); ok && len(host) > 0 {
  353. params["host"] = host
  354. } else {
  355. headers, _ := ws["headers"].(map[string]any)
  356. params["host"] = searchHost(headers)
  357. }
  358. case "grpc":
  359. grpc, _ := stream["grpcSettings"].(map[string]any)
  360. params["serviceName"] = grpc["serviceName"].(string)
  361. params["authority"], _ = grpc["authority"].(string)
  362. if grpc["multiMode"].(bool) {
  363. params["mode"] = "multi"
  364. }
  365. case "httpupgrade":
  366. httpupgrade, _ := stream["httpupgradeSettings"].(map[string]any)
  367. params["path"] = httpupgrade["path"].(string)
  368. if host, ok := httpupgrade["host"].(string); ok && len(host) > 0 {
  369. params["host"] = host
  370. } else {
  371. headers, _ := httpupgrade["headers"].(map[string]any)
  372. params["host"] = searchHost(headers)
  373. }
  374. case "xhttp":
  375. xhttp, _ := stream["xhttpSettings"].(map[string]any)
  376. params["path"] = xhttp["path"].(string)
  377. if host, ok := xhttp["host"].(string); ok && len(host) > 0 {
  378. params["host"] = host
  379. } else {
  380. headers, _ := xhttp["headers"].(map[string]any)
  381. params["host"] = searchHost(headers)
  382. }
  383. params["mode"], _ = xhttp["mode"].(string)
  384. }
  385. security, _ := stream["security"].(string)
  386. if security == "tls" {
  387. params["security"] = "tls"
  388. tlsSetting, _ := stream["tlsSettings"].(map[string]any)
  389. alpns, _ := tlsSetting["alpn"].([]any)
  390. var alpn []string
  391. for _, a := range alpns {
  392. alpn = append(alpn, a.(string))
  393. }
  394. if len(alpn) > 0 {
  395. params["alpn"] = strings.Join(alpn, ",")
  396. }
  397. if sniValue, ok := searchKey(tlsSetting, "serverName"); ok {
  398. params["sni"], _ = sniValue.(string)
  399. }
  400. tlsSettings, _ := searchKey(tlsSetting, "settings")
  401. if tlsSetting != nil {
  402. if fpValue, ok := searchKey(tlsSettings, "fingerprint"); ok {
  403. params["fp"], _ = fpValue.(string)
  404. }
  405. }
  406. if streamNetwork == "tcp" && len(clients[clientIndex].Flow) > 0 {
  407. params["flow"] = clients[clientIndex].Flow
  408. }
  409. }
  410. if security == "reality" {
  411. params["security"] = "reality"
  412. realitySetting, _ := stream["realitySettings"].(map[string]any)
  413. realitySettings, _ := searchKey(realitySetting, "settings")
  414. if realitySetting != nil {
  415. if sniValue, ok := searchKey(realitySetting, "serverNames"); ok {
  416. sNames, _ := sniValue.([]any)
  417. params["sni"] = sNames[random.Num(len(sNames))].(string)
  418. }
  419. if pbkValue, ok := searchKey(realitySettings, "publicKey"); ok {
  420. params["pbk"], _ = pbkValue.(string)
  421. }
  422. if sidValue, ok := searchKey(realitySetting, "shortIds"); ok {
  423. shortIds, _ := sidValue.([]any)
  424. params["sid"] = shortIds[random.Num(len(shortIds))].(string)
  425. }
  426. if fpValue, ok := searchKey(realitySettings, "fingerprint"); ok {
  427. if fp, ok := fpValue.(string); ok && len(fp) > 0 {
  428. params["fp"] = fp
  429. }
  430. }
  431. if pqvValue, ok := searchKey(realitySettings, "mldsa65Verify"); ok {
  432. if pqv, ok := pqvValue.(string); ok && len(pqv) > 0 {
  433. params["pqv"] = pqv
  434. }
  435. }
  436. params["spx"] = "/" + random.Seq(15)
  437. }
  438. if streamNetwork == "tcp" && len(clients[clientIndex].Flow) > 0 {
  439. params["flow"] = clients[clientIndex].Flow
  440. }
  441. }
  442. if security != "tls" && security != "reality" {
  443. params["security"] = "none"
  444. }
  445. externalProxies, _ := stream["externalProxy"].([]any)
  446. if len(externalProxies) > 0 {
  447. links := make([]string, 0, len(externalProxies))
  448. for _, externalProxy := range externalProxies {
  449. ep, _ := externalProxy.(map[string]any)
  450. newSecurity, _ := ep["forceTls"].(string)
  451. dest, _ := ep["dest"].(string)
  452. port := int(ep["port"].(float64))
  453. link := fmt.Sprintf("vless://%s@%s:%d", uuid, dest, port)
  454. if newSecurity != "same" {
  455. params["security"] = newSecurity
  456. } else {
  457. params["security"] = security
  458. }
  459. url, _ := url.Parse(link)
  460. q := url.Query()
  461. for k, v := range params {
  462. if !(newSecurity == "none" && (k == "alpn" || k == "sni" || k == "fp")) {
  463. q.Add(k, v)
  464. }
  465. }
  466. // Set the new query values on the URL
  467. url.RawQuery = q.Encode()
  468. url.Fragment = s.genRemark(inbound, email, ep["remark"].(string))
  469. links = append(links, url.String())
  470. }
  471. return strings.Join(links, "\n")
  472. }
  473. link := fmt.Sprintf("vless://%s@%s:%d", uuid, address, port)
  474. url, _ := url.Parse(link)
  475. q := url.Query()
  476. for k, v := range params {
  477. q.Add(k, v)
  478. }
  479. // Set the new query values on the URL
  480. url.RawQuery = q.Encode()
  481. url.Fragment = s.genRemark(inbound, email, "")
  482. return url.String()
  483. }
  484. func (s *SubService) genTrojanLink(inbound *model.Inbound, email string) string {
  485. var address string
  486. if inbound.Listen == "" || inbound.Listen == "0.0.0.0" || inbound.Listen == "::" || inbound.Listen == "::0" {
  487. address = s.address
  488. } else {
  489. address = inbound.Listen
  490. }
  491. if inbound.Protocol != model.Trojan {
  492. return ""
  493. }
  494. var stream map[string]any
  495. json.Unmarshal([]byte(inbound.StreamSettings), &stream)
  496. clients, _ := s.inboundService.GetClients(inbound)
  497. clientIndex := -1
  498. for i, client := range clients {
  499. if client.Email == email {
  500. clientIndex = i
  501. break
  502. }
  503. }
  504. password := clients[clientIndex].Password
  505. port := inbound.Port
  506. streamNetwork := stream["network"].(string)
  507. params := make(map[string]string)
  508. params["type"] = streamNetwork
  509. switch streamNetwork {
  510. case "tcp":
  511. tcp, _ := stream["tcpSettings"].(map[string]any)
  512. header, _ := tcp["header"].(map[string]any)
  513. typeStr, _ := header["type"].(string)
  514. if typeStr == "http" {
  515. request := header["request"].(map[string]any)
  516. requestPath, _ := request["path"].([]any)
  517. params["path"] = requestPath[0].(string)
  518. headers, _ := request["headers"].(map[string]any)
  519. params["host"] = searchHost(headers)
  520. params["headerType"] = "http"
  521. }
  522. case "kcp":
  523. kcp, _ := stream["kcpSettings"].(map[string]any)
  524. header, _ := kcp["header"].(map[string]any)
  525. params["headerType"] = header["type"].(string)
  526. params["seed"] = kcp["seed"].(string)
  527. case "ws":
  528. ws, _ := stream["wsSettings"].(map[string]any)
  529. params["path"] = ws["path"].(string)
  530. if host, ok := ws["host"].(string); ok && len(host) > 0 {
  531. params["host"] = host
  532. } else {
  533. headers, _ := ws["headers"].(map[string]any)
  534. params["host"] = searchHost(headers)
  535. }
  536. case "grpc":
  537. grpc, _ := stream["grpcSettings"].(map[string]any)
  538. params["serviceName"] = grpc["serviceName"].(string)
  539. params["authority"], _ = grpc["authority"].(string)
  540. if grpc["multiMode"].(bool) {
  541. params["mode"] = "multi"
  542. }
  543. case "httpupgrade":
  544. httpupgrade, _ := stream["httpupgradeSettings"].(map[string]any)
  545. params["path"] = httpupgrade["path"].(string)
  546. if host, ok := httpupgrade["host"].(string); ok && len(host) > 0 {
  547. params["host"] = host
  548. } else {
  549. headers, _ := httpupgrade["headers"].(map[string]any)
  550. params["host"] = searchHost(headers)
  551. }
  552. case "xhttp":
  553. xhttp, _ := stream["xhttpSettings"].(map[string]any)
  554. params["path"] = xhttp["path"].(string)
  555. if host, ok := xhttp["host"].(string); ok && len(host) > 0 {
  556. params["host"] = host
  557. } else {
  558. headers, _ := xhttp["headers"].(map[string]any)
  559. params["host"] = searchHost(headers)
  560. }
  561. params["mode"], _ = xhttp["mode"].(string)
  562. }
  563. security, _ := stream["security"].(string)
  564. if security == "tls" {
  565. params["security"] = "tls"
  566. tlsSetting, _ := stream["tlsSettings"].(map[string]any)
  567. alpns, _ := tlsSetting["alpn"].([]any)
  568. var alpn []string
  569. for _, a := range alpns {
  570. alpn = append(alpn, a.(string))
  571. }
  572. if len(alpn) > 0 {
  573. params["alpn"] = strings.Join(alpn, ",")
  574. }
  575. if sniValue, ok := searchKey(tlsSetting, "serverName"); ok {
  576. params["sni"], _ = sniValue.(string)
  577. }
  578. tlsSettings, _ := searchKey(tlsSetting, "settings")
  579. if tlsSetting != nil {
  580. if fpValue, ok := searchKey(tlsSettings, "fingerprint"); ok {
  581. params["fp"], _ = fpValue.(string)
  582. }
  583. }
  584. }
  585. if security == "reality" {
  586. params["security"] = "reality"
  587. realitySetting, _ := stream["realitySettings"].(map[string]any)
  588. realitySettings, _ := searchKey(realitySetting, "settings")
  589. if realitySetting != nil {
  590. if sniValue, ok := searchKey(realitySetting, "serverNames"); ok {
  591. sNames, _ := sniValue.([]any)
  592. params["sni"] = sNames[random.Num(len(sNames))].(string)
  593. }
  594. if pbkValue, ok := searchKey(realitySettings, "publicKey"); ok {
  595. params["pbk"], _ = pbkValue.(string)
  596. }
  597. if sidValue, ok := searchKey(realitySetting, "shortIds"); ok {
  598. shortIds, _ := sidValue.([]any)
  599. params["sid"] = shortIds[random.Num(len(shortIds))].(string)
  600. }
  601. if fpValue, ok := searchKey(realitySettings, "fingerprint"); ok {
  602. if fp, ok := fpValue.(string); ok && len(fp) > 0 {
  603. params["fp"] = fp
  604. }
  605. }
  606. if pqvValue, ok := searchKey(realitySettings, "mldsa65Verify"); ok {
  607. if pqv, ok := pqvValue.(string); ok && len(pqv) > 0 {
  608. params["pqv"] = pqv
  609. }
  610. }
  611. params["spx"] = "/" + random.Seq(15)
  612. }
  613. if streamNetwork == "tcp" && len(clients[clientIndex].Flow) > 0 {
  614. params["flow"] = clients[clientIndex].Flow
  615. }
  616. }
  617. if security != "tls" && security != "reality" {
  618. params["security"] = "none"
  619. }
  620. externalProxies, _ := stream["externalProxy"].([]any)
  621. if len(externalProxies) > 0 {
  622. links := ""
  623. for index, externalProxy := range externalProxies {
  624. ep, _ := externalProxy.(map[string]any)
  625. newSecurity, _ := ep["forceTls"].(string)
  626. dest, _ := ep["dest"].(string)
  627. port := int(ep["port"].(float64))
  628. link := fmt.Sprintf("trojan://%s@%s:%d", password, dest, port)
  629. if newSecurity != "same" {
  630. params["security"] = newSecurity
  631. } else {
  632. params["security"] = security
  633. }
  634. url, _ := url.Parse(link)
  635. q := url.Query()
  636. for k, v := range params {
  637. if !(newSecurity == "none" && (k == "alpn" || k == "sni" || k == "fp")) {
  638. q.Add(k, v)
  639. }
  640. }
  641. // Set the new query values on the URL
  642. url.RawQuery = q.Encode()
  643. url.Fragment = s.genRemark(inbound, email, ep["remark"].(string))
  644. if index > 0 {
  645. links += "\n"
  646. }
  647. links += url.String()
  648. }
  649. return links
  650. }
  651. link := fmt.Sprintf("trojan://%s@%s:%d", password, address, port)
  652. url, _ := url.Parse(link)
  653. q := url.Query()
  654. for k, v := range params {
  655. q.Add(k, v)
  656. }
  657. // Set the new query values on the URL
  658. url.RawQuery = q.Encode()
  659. url.Fragment = s.genRemark(inbound, email, "")
  660. return url.String()
  661. }
  662. func (s *SubService) genShadowsocksLink(inbound *model.Inbound, email string) string {
  663. var address string
  664. if inbound.Listen == "" || inbound.Listen == "0.0.0.0" || inbound.Listen == "::" || inbound.Listen == "::0" {
  665. address = s.address
  666. } else {
  667. address = inbound.Listen
  668. }
  669. if inbound.Protocol != model.Shadowsocks {
  670. return ""
  671. }
  672. var stream map[string]any
  673. json.Unmarshal([]byte(inbound.StreamSettings), &stream)
  674. clients, _ := s.inboundService.GetClients(inbound)
  675. var settings map[string]any
  676. json.Unmarshal([]byte(inbound.Settings), &settings)
  677. inboundPassword := settings["password"].(string)
  678. method := settings["method"].(string)
  679. clientIndex := -1
  680. for i, client := range clients {
  681. if client.Email == email {
  682. clientIndex = i
  683. break
  684. }
  685. }
  686. streamNetwork := stream["network"].(string)
  687. params := make(map[string]string)
  688. params["type"] = streamNetwork
  689. switch streamNetwork {
  690. case "tcp":
  691. tcp, _ := stream["tcpSettings"].(map[string]any)
  692. header, _ := tcp["header"].(map[string]any)
  693. typeStr, _ := header["type"].(string)
  694. if typeStr == "http" {
  695. request := header["request"].(map[string]any)
  696. requestPath, _ := request["path"].([]any)
  697. params["path"] = requestPath[0].(string)
  698. headers, _ := request["headers"].(map[string]any)
  699. params["host"] = searchHost(headers)
  700. params["headerType"] = "http"
  701. }
  702. case "kcp":
  703. kcp, _ := stream["kcpSettings"].(map[string]any)
  704. header, _ := kcp["header"].(map[string]any)
  705. params["headerType"] = header["type"].(string)
  706. params["seed"] = kcp["seed"].(string)
  707. case "ws":
  708. ws, _ := stream["wsSettings"].(map[string]any)
  709. params["path"] = ws["path"].(string)
  710. if host, ok := ws["host"].(string); ok && len(host) > 0 {
  711. params["host"] = host
  712. } else {
  713. headers, _ := ws["headers"].(map[string]any)
  714. params["host"] = searchHost(headers)
  715. }
  716. case "grpc":
  717. grpc, _ := stream["grpcSettings"].(map[string]any)
  718. params["serviceName"] = grpc["serviceName"].(string)
  719. params["authority"], _ = grpc["authority"].(string)
  720. if grpc["multiMode"].(bool) {
  721. params["mode"] = "multi"
  722. }
  723. case "httpupgrade":
  724. httpupgrade, _ := stream["httpupgradeSettings"].(map[string]any)
  725. params["path"] = httpupgrade["path"].(string)
  726. if host, ok := httpupgrade["host"].(string); ok && len(host) > 0 {
  727. params["host"] = host
  728. } else {
  729. headers, _ := httpupgrade["headers"].(map[string]any)
  730. params["host"] = searchHost(headers)
  731. }
  732. case "xhttp":
  733. xhttp, _ := stream["xhttpSettings"].(map[string]any)
  734. params["path"] = xhttp["path"].(string)
  735. if host, ok := xhttp["host"].(string); ok && len(host) > 0 {
  736. params["host"] = host
  737. } else {
  738. headers, _ := xhttp["headers"].(map[string]any)
  739. params["host"] = searchHost(headers)
  740. }
  741. params["mode"], _ = xhttp["mode"].(string)
  742. }
  743. security, _ := stream["security"].(string)
  744. if security == "tls" {
  745. params["security"] = "tls"
  746. tlsSetting, _ := stream["tlsSettings"].(map[string]any)
  747. alpns, _ := tlsSetting["alpn"].([]any)
  748. var alpn []string
  749. for _, a := range alpns {
  750. alpn = append(alpn, a.(string))
  751. }
  752. if len(alpn) > 0 {
  753. params["alpn"] = strings.Join(alpn, ",")
  754. }
  755. if sniValue, ok := searchKey(tlsSetting, "serverName"); ok {
  756. params["sni"], _ = sniValue.(string)
  757. }
  758. tlsSettings, _ := searchKey(tlsSetting, "settings")
  759. if tlsSetting != nil {
  760. if fpValue, ok := searchKey(tlsSettings, "fingerprint"); ok {
  761. params["fp"], _ = fpValue.(string)
  762. }
  763. }
  764. }
  765. encPart := fmt.Sprintf("%s:%s", method, clients[clientIndex].Password)
  766. if method[0] == '2' {
  767. encPart = fmt.Sprintf("%s:%s:%s", method, inboundPassword, clients[clientIndex].Password)
  768. }
  769. externalProxies, _ := stream["externalProxy"].([]any)
  770. if len(externalProxies) > 0 {
  771. links := ""
  772. for index, externalProxy := range externalProxies {
  773. ep, _ := externalProxy.(map[string]any)
  774. newSecurity, _ := ep["forceTls"].(string)
  775. dest, _ := ep["dest"].(string)
  776. port := int(ep["port"].(float64))
  777. link := fmt.Sprintf("ss://%s@%s:%d", base64.StdEncoding.EncodeToString([]byte(encPart)), dest, port)
  778. if newSecurity != "same" {
  779. params["security"] = newSecurity
  780. } else {
  781. params["security"] = security
  782. }
  783. url, _ := url.Parse(link)
  784. q := url.Query()
  785. for k, v := range params {
  786. if !(newSecurity == "none" && (k == "alpn" || k == "sni" || k == "fp")) {
  787. q.Add(k, v)
  788. }
  789. }
  790. // Set the new query values on the URL
  791. url.RawQuery = q.Encode()
  792. url.Fragment = s.genRemark(inbound, email, ep["remark"].(string))
  793. if index > 0 {
  794. links += "\n"
  795. }
  796. links += url.String()
  797. }
  798. return links
  799. }
  800. link := fmt.Sprintf("ss://%s@%s:%d", base64.StdEncoding.EncodeToString([]byte(encPart)), address, inbound.Port)
  801. url, _ := url.Parse(link)
  802. q := url.Query()
  803. for k, v := range params {
  804. q.Add(k, v)
  805. }
  806. // Set the new query values on the URL
  807. url.RawQuery = q.Encode()
  808. url.Fragment = s.genRemark(inbound, email, "")
  809. return url.String()
  810. }
  811. func (s *SubService) genHysteriaLink(inbound *model.Inbound, email string) string {
  812. address := s.address
  813. if inbound.Protocol != model.Hysteria {
  814. return ""
  815. }
  816. var stream map[string]interface{}
  817. json.Unmarshal([]byte(inbound.StreamSettings), &stream)
  818. clients, _ := s.inboundService.GetClients(inbound)
  819. clientIndex := -1
  820. for i, client := range clients {
  821. if client.Email == email {
  822. clientIndex = i
  823. break
  824. }
  825. }
  826. auth := clients[clientIndex].Auth
  827. port := inbound.Port
  828. params := make(map[string]string)
  829. params["security"] = "tls"
  830. tlsSetting, _ := stream["tlsSettings"].(map[string]interface{})
  831. alpns, _ := tlsSetting["alpn"].([]interface{})
  832. var alpn []string
  833. for _, a := range alpns {
  834. alpn = append(alpn, a.(string))
  835. }
  836. if len(alpn) > 0 {
  837. params["alpn"] = strings.Join(alpn, ",")
  838. }
  839. if sniValue, ok := searchKey(tlsSetting, "serverName"); ok {
  840. params["sni"], _ = sniValue.(string)
  841. }
  842. tlsSettings, _ := searchKey(tlsSetting, "settings")
  843. if tlsSetting != nil {
  844. if fpValue, ok := searchKey(tlsSettings, "fingerprint"); ok {
  845. params["fp"], _ = fpValue.(string)
  846. }
  847. if insecure, ok := searchKey(tlsSettings, "allowInsecure"); ok {
  848. if insecure.(bool) {
  849. params["insecure"] = "1"
  850. }
  851. }
  852. }
  853. var settings map[string]interface{}
  854. json.Unmarshal([]byte(inbound.Settings), &settings)
  855. version, _ := settings["version"].(float64)
  856. protocol := "hysteria2"
  857. if int(version) == 1 {
  858. protocol = "hysteria"
  859. }
  860. link := fmt.Sprintf("%s://%s@%s:%d", protocol, auth, address, port)
  861. url, _ := url.Parse(link)
  862. q := url.Query()
  863. for k, v := range params {
  864. q.Add(k, v)
  865. }
  866. url.RawQuery = q.Encode()
  867. url.Fragment = s.genRemark(inbound, email, "")
  868. return url.String()
  869. }
  870. func (s *SubService) genRemark(inbound *model.Inbound, email string, extra string) string {
  871. separationChar := string(s.remarkModel[0])
  872. orderChars := s.remarkModel[1:]
  873. orders := map[byte]string{
  874. 'i': "",
  875. 'e': "",
  876. 'o': "",
  877. }
  878. if len(email) > 0 {
  879. orders['e'] = email
  880. }
  881. if len(inbound.Remark) > 0 {
  882. orders['i'] = inbound.Remark
  883. }
  884. if len(extra) > 0 {
  885. orders['o'] = extra
  886. }
  887. var remark []string
  888. for i := 0; i < len(orderChars); i++ {
  889. char := orderChars[i]
  890. order, exists := orders[char]
  891. if exists && order != "" {
  892. remark = append(remark, order)
  893. }
  894. }
  895. if s.showInfo {
  896. statsExist := false
  897. var stats xray.ClientTraffic
  898. for _, clientStat := range inbound.ClientStats {
  899. if clientStat.Email == email {
  900. stats = clientStat
  901. statsExist = true
  902. break
  903. }
  904. }
  905. // Get remained days
  906. if statsExist {
  907. if !stats.Enable {
  908. return fmt.Sprintf("⛔️N/A%s%s", separationChar, strings.Join(remark, separationChar))
  909. }
  910. if vol := stats.Total - (stats.Up + stats.Down); vol > 0 {
  911. remark = append(remark, fmt.Sprintf("%s%s", common.FormatTraffic(vol), "📊"))
  912. }
  913. now := time.Now().Unix()
  914. switch exp := stats.ExpiryTime / 1000; {
  915. case exp > 0:
  916. remainingSeconds := exp - now
  917. days := remainingSeconds / 86400
  918. hours := (remainingSeconds % 86400) / 3600
  919. minutes := (remainingSeconds % 3600) / 60
  920. if days > 0 {
  921. if hours > 0 {
  922. remark = append(remark, fmt.Sprintf("%dD,%dH⏳", days, hours))
  923. } else {
  924. remark = append(remark, fmt.Sprintf("%dD⏳", days))
  925. }
  926. } else if hours > 0 {
  927. remark = append(remark, fmt.Sprintf("%dH⏳", hours))
  928. } else {
  929. remark = append(remark, fmt.Sprintf("%dM⏳", minutes))
  930. }
  931. case exp < 0:
  932. days := exp / -86400
  933. hours := (exp % -86400) / 3600
  934. minutes := (exp % -3600) / 60
  935. if days > 0 {
  936. if hours > 0 {
  937. remark = append(remark, fmt.Sprintf("%dD,%dH⏳", days, hours))
  938. } else {
  939. remark = append(remark, fmt.Sprintf("%dD⏳", days))
  940. }
  941. } else if hours > 0 {
  942. remark = append(remark, fmt.Sprintf("%dH⏳", hours))
  943. } else {
  944. remark = append(remark, fmt.Sprintf("%dM⏳", minutes))
  945. }
  946. }
  947. }
  948. }
  949. return strings.Join(remark, separationChar)
  950. }
  951. func searchKey(data any, key string) (any, bool) {
  952. switch val := data.(type) {
  953. case map[string]any:
  954. for k, v := range val {
  955. if k == key {
  956. return v, true
  957. }
  958. if result, ok := searchKey(v, key); ok {
  959. return result, true
  960. }
  961. }
  962. case []any:
  963. for _, v := range val {
  964. if result, ok := searchKey(v, key); ok {
  965. return result, true
  966. }
  967. }
  968. }
  969. return nil, false
  970. }
  971. func searchHost(headers any) string {
  972. data, _ := headers.(map[string]any)
  973. for k, v := range data {
  974. if strings.EqualFold(k, "host") {
  975. switch v.(type) {
  976. case []any:
  977. hosts, _ := v.([]any)
  978. if len(hosts) > 0 {
  979. return hosts[0].(string)
  980. } else {
  981. return ""
  982. }
  983. case any:
  984. return v.(string)
  985. }
  986. }
  987. }
  988. return ""
  989. }
  990. // PageData is a view model for subpage.html
  991. // PageData contains data for rendering the subscription information page.
  992. type PageData struct {
  993. Host string
  994. BasePath string
  995. SId string
  996. Download string
  997. Upload string
  998. Total string
  999. Used string
  1000. Remained string
  1001. Expire int64
  1002. LastOnline int64
  1003. Datepicker string
  1004. DownloadByte int64
  1005. UploadByte int64
  1006. TotalByte int64
  1007. SubUrl string
  1008. SubJsonUrl string
  1009. SubClashUrl string
  1010. Result []string
  1011. }
  1012. // ResolveRequest extracts scheme and host info from request/headers consistently.
  1013. // ResolveRequest extracts scheme, host, and header information from an HTTP request.
  1014. func (s *SubService) ResolveRequest(c *gin.Context) (scheme string, host string, hostWithPort string, hostHeader string) {
  1015. // scheme
  1016. scheme = "http"
  1017. if c.Request.TLS != nil || strings.EqualFold(c.GetHeader("X-Forwarded-Proto"), "https") {
  1018. scheme = "https"
  1019. }
  1020. // base host (no port)
  1021. if h, err := getHostFromXFH(c.GetHeader("X-Forwarded-Host")); err == nil && h != "" {
  1022. host = h
  1023. }
  1024. if host == "" {
  1025. host = c.GetHeader("X-Real-IP")
  1026. }
  1027. if host == "" {
  1028. var err error
  1029. host, _, err = net.SplitHostPort(c.Request.Host)
  1030. if err != nil {
  1031. host = c.Request.Host
  1032. }
  1033. }
  1034. // host:port for URLs
  1035. hostWithPort = c.GetHeader("X-Forwarded-Host")
  1036. if hostWithPort == "" {
  1037. hostWithPort = c.Request.Host
  1038. }
  1039. if hostWithPort == "" {
  1040. hostWithPort = host
  1041. }
  1042. // header display host
  1043. hostHeader = c.GetHeader("X-Forwarded-Host")
  1044. if hostHeader == "" {
  1045. hostHeader = c.GetHeader("X-Real-IP")
  1046. }
  1047. if hostHeader == "" {
  1048. hostHeader = host
  1049. }
  1050. return
  1051. }
  1052. // BuildURLs constructs absolute subscription and JSON subscription URLs for a given subscription ID.
  1053. // It prioritizes configured URIs, then individual settings, and finally falls back to request-derived components.
  1054. func (s *SubService) BuildURLs(scheme, hostWithPort, subPath, subJsonPath, subClashPath, subId string) (subURL, subJsonURL, subClashURL string) {
  1055. if subId == "" {
  1056. return "", "", ""
  1057. }
  1058. configuredSubURI, _ := s.settingService.GetSubURI()
  1059. configuredSubJsonURI, _ := s.settingService.GetSubJsonURI()
  1060. configuredSubClashURI, _ := s.settingService.GetSubClashURI()
  1061. var baseScheme, baseHostWithPort string
  1062. if configuredSubURI == "" || configuredSubJsonURI == "" || configuredSubClashURI == "" {
  1063. baseScheme, baseHostWithPort = s.getBaseSchemeAndHost(scheme, hostWithPort)
  1064. }
  1065. subURL = s.buildSingleURL(configuredSubURI, baseScheme, baseHostWithPort, subPath, subId)
  1066. subJsonURL = s.buildSingleURL(configuredSubJsonURI, baseScheme, baseHostWithPort, subJsonPath, subId)
  1067. subClashURL = s.buildSingleURL(configuredSubClashURI, baseScheme, baseHostWithPort, subClashPath, subId)
  1068. return subURL, subJsonURL, subClashURL
  1069. }
  1070. // getBaseSchemeAndHost determines the base scheme and host from settings or falls back to request values
  1071. func (s *SubService) getBaseSchemeAndHost(requestScheme, requestHostWithPort string) (string, string) {
  1072. subDomain, err := s.settingService.GetSubDomain()
  1073. if err != nil || subDomain == "" {
  1074. return requestScheme, requestHostWithPort
  1075. }
  1076. // Get port and TLS settings
  1077. subPort, _ := s.settingService.GetSubPort()
  1078. subKeyFile, _ := s.settingService.GetSubKeyFile()
  1079. subCertFile, _ := s.settingService.GetSubCertFile()
  1080. // Determine scheme from TLS configuration
  1081. scheme := "http"
  1082. if subKeyFile != "" && subCertFile != "" {
  1083. scheme = "https"
  1084. }
  1085. // Build host:port, always include port for clarity
  1086. hostWithPort := fmt.Sprintf("%s:%d", subDomain, subPort)
  1087. return scheme, hostWithPort
  1088. }
  1089. // buildSingleURL constructs a single URL using configured URI or base components
  1090. func (s *SubService) buildSingleURL(configuredURI, baseScheme, baseHostWithPort, basePath, subId string) string {
  1091. if configuredURI != "" {
  1092. return s.joinPathWithID(configuredURI, subId)
  1093. }
  1094. baseURL := fmt.Sprintf("%s://%s", baseScheme, baseHostWithPort)
  1095. return s.joinPathWithID(baseURL+basePath, subId)
  1096. }
  1097. // joinPathWithID safely joins a base path with a subscription ID
  1098. func (s *SubService) joinPathWithID(basePath, subId string) string {
  1099. if strings.HasSuffix(basePath, "/") {
  1100. return basePath + subId
  1101. }
  1102. return basePath + "/" + subId
  1103. }
  1104. // BuildPageData parses header and prepares the template view model.
  1105. // BuildPageData constructs page data for rendering the subscription information page.
  1106. func (s *SubService) BuildPageData(subId string, hostHeader string, traffic xray.ClientTraffic, lastOnline int64, subs []string, subURL, subJsonURL, subClashURL string, basePath string) PageData {
  1107. download := common.FormatTraffic(traffic.Down)
  1108. upload := common.FormatTraffic(traffic.Up)
  1109. total := "∞"
  1110. used := common.FormatTraffic(traffic.Up + traffic.Down)
  1111. remained := ""
  1112. if traffic.Total > 0 {
  1113. total = common.FormatTraffic(traffic.Total)
  1114. left := max(traffic.Total-(traffic.Up+traffic.Down), 0)
  1115. remained = common.FormatTraffic(left)
  1116. }
  1117. datepicker := s.datepicker
  1118. if datepicker == "" {
  1119. datepicker = "gregorian"
  1120. }
  1121. return PageData{
  1122. Host: hostHeader,
  1123. BasePath: basePath,
  1124. SId: subId,
  1125. Download: download,
  1126. Upload: upload,
  1127. Total: total,
  1128. Used: used,
  1129. Remained: remained,
  1130. Expire: traffic.ExpiryTime / 1000,
  1131. LastOnline: lastOnline,
  1132. Datepicker: datepicker,
  1133. DownloadByte: traffic.Down,
  1134. UploadByte: traffic.Up,
  1135. TotalByte: traffic.Total,
  1136. SubUrl: subURL,
  1137. SubJsonUrl: subJsonURL,
  1138. SubClashUrl: subClashURL,
  1139. Result: subs,
  1140. }
  1141. }
  1142. func getHostFromXFH(s string) (string, error) {
  1143. if strings.Contains(s, ":") {
  1144. realHost, _, err := net.SplitHostPort(s)
  1145. if err != nil {
  1146. return "", err
  1147. }
  1148. return realHost, nil
  1149. }
  1150. return s, nil
  1151. }