subService.go 32 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148
  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')
  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. }
  160. return ""
  161. }
  162. func (s *SubService) genVmessLink(inbound *model.Inbound, email string) string {
  163. if inbound.Protocol != model.VMESS {
  164. return ""
  165. }
  166. obj := map[string]any{
  167. "v": "2",
  168. "add": s.address,
  169. "port": inbound.Port,
  170. "type": "none",
  171. }
  172. var stream map[string]any
  173. json.Unmarshal([]byte(inbound.StreamSettings), &stream)
  174. network, _ := stream["network"].(string)
  175. obj["net"] = network
  176. switch network {
  177. case "tcp":
  178. tcp, _ := stream["tcpSettings"].(map[string]any)
  179. header, _ := tcp["header"].(map[string]any)
  180. typeStr, _ := header["type"].(string)
  181. obj["type"] = typeStr
  182. if typeStr == "http" {
  183. request := header["request"].(map[string]any)
  184. requestPath, _ := request["path"].([]any)
  185. obj["path"] = requestPath[0].(string)
  186. headers, _ := request["headers"].(map[string]any)
  187. obj["host"] = searchHost(headers)
  188. }
  189. case "kcp":
  190. kcp, _ := stream["kcpSettings"].(map[string]any)
  191. header, _ := kcp["header"].(map[string]any)
  192. obj["type"], _ = header["type"].(string)
  193. obj["path"], _ = kcp["seed"].(string)
  194. case "ws":
  195. ws, _ := stream["wsSettings"].(map[string]any)
  196. obj["path"] = ws["path"].(string)
  197. if host, ok := ws["host"].(string); ok && len(host) > 0 {
  198. obj["host"] = host
  199. } else {
  200. headers, _ := ws["headers"].(map[string]any)
  201. obj["host"] = searchHost(headers)
  202. }
  203. case "grpc":
  204. grpc, _ := stream["grpcSettings"].(map[string]any)
  205. obj["path"] = grpc["serviceName"].(string)
  206. obj["authority"] = grpc["authority"].(string)
  207. if grpc["multiMode"].(bool) {
  208. obj["type"] = "multi"
  209. }
  210. case "httpupgrade":
  211. httpupgrade, _ := stream["httpupgradeSettings"].(map[string]any)
  212. obj["path"] = httpupgrade["path"].(string)
  213. if host, ok := httpupgrade["host"].(string); ok && len(host) > 0 {
  214. obj["host"] = host
  215. } else {
  216. headers, _ := httpupgrade["headers"].(map[string]any)
  217. obj["host"] = searchHost(headers)
  218. }
  219. case "xhttp":
  220. xhttp, _ := stream["xhttpSettings"].(map[string]any)
  221. obj["path"] = xhttp["path"].(string)
  222. if host, ok := xhttp["host"].(string); ok && len(host) > 0 {
  223. obj["host"] = host
  224. } else {
  225. headers, _ := xhttp["headers"].(map[string]any)
  226. obj["host"] = searchHost(headers)
  227. }
  228. obj["mode"] = xhttp["mode"].(string)
  229. }
  230. security, _ := stream["security"].(string)
  231. obj["tls"] = security
  232. if security == "tls" {
  233. tlsSetting, _ := stream["tlsSettings"].(map[string]any)
  234. alpns, _ := tlsSetting["alpn"].([]any)
  235. if len(alpns) > 0 {
  236. var alpn []string
  237. for _, a := range alpns {
  238. alpn = append(alpn, a.(string))
  239. }
  240. obj["alpn"] = strings.Join(alpn, ",")
  241. }
  242. if sniValue, ok := searchKey(tlsSetting, "serverName"); ok {
  243. obj["sni"], _ = sniValue.(string)
  244. }
  245. tlsSettings, _ := searchKey(tlsSetting, "settings")
  246. if tlsSetting != nil {
  247. if fpValue, ok := searchKey(tlsSettings, "fingerprint"); ok {
  248. obj["fp"], _ = fpValue.(string)
  249. }
  250. if insecure, ok := searchKey(tlsSettings, "allowInsecure"); ok {
  251. obj["allowInsecure"], _ = insecure.(bool)
  252. }
  253. }
  254. }
  255. clients, _ := s.inboundService.GetClients(inbound)
  256. clientIndex := -1
  257. for i, client := range clients {
  258. if client.Email == email {
  259. clientIndex = i
  260. break
  261. }
  262. }
  263. obj["id"] = clients[clientIndex].ID
  264. obj["scy"] = clients[clientIndex].Security
  265. externalProxies, _ := stream["externalProxy"].([]any)
  266. if len(externalProxies) > 0 {
  267. links := ""
  268. for index, externalProxy := range externalProxies {
  269. ep, _ := externalProxy.(map[string]any)
  270. newSecurity, _ := ep["forceTls"].(string)
  271. newObj := map[string]any{}
  272. for key, value := range obj {
  273. if !(newSecurity == "none" && (key == "alpn" || key == "sni" || key == "fp" || key == "allowInsecure")) {
  274. newObj[key] = value
  275. }
  276. }
  277. newObj["ps"] = s.genRemark(inbound, email, ep["remark"].(string))
  278. newObj["add"] = ep["dest"].(string)
  279. newObj["port"] = int(ep["port"].(float64))
  280. if newSecurity != "same" {
  281. newObj["tls"] = newSecurity
  282. }
  283. if index > 0 {
  284. links += "\n"
  285. }
  286. jsonStr, _ := json.MarshalIndent(newObj, "", " ")
  287. links += "vmess://" + base64.StdEncoding.EncodeToString(jsonStr)
  288. }
  289. return links
  290. }
  291. obj["ps"] = s.genRemark(inbound, email, "")
  292. jsonStr, _ := json.MarshalIndent(obj, "", " ")
  293. return "vmess://" + base64.StdEncoding.EncodeToString(jsonStr)
  294. }
  295. func (s *SubService) genVlessLink(inbound *model.Inbound, email string) string {
  296. address := s.address
  297. if inbound.Protocol != model.VLESS {
  298. return ""
  299. }
  300. var stream map[string]any
  301. json.Unmarshal([]byte(inbound.StreamSettings), &stream)
  302. clients, _ := s.inboundService.GetClients(inbound)
  303. clientIndex := -1
  304. for i, client := range clients {
  305. if client.Email == email {
  306. clientIndex = i
  307. break
  308. }
  309. }
  310. uuid := clients[clientIndex].ID
  311. port := inbound.Port
  312. streamNetwork := stream["network"].(string)
  313. params := make(map[string]string)
  314. params["type"] = streamNetwork
  315. // Add encryption parameter for VLESS from inbound settings
  316. var settings map[string]any
  317. json.Unmarshal([]byte(inbound.Settings), &settings)
  318. if encryption, ok := settings["encryption"].(string); ok {
  319. params["encryption"] = encryption
  320. }
  321. switch streamNetwork {
  322. case "tcp":
  323. tcp, _ := stream["tcpSettings"].(map[string]any)
  324. header, _ := tcp["header"].(map[string]any)
  325. typeStr, _ := header["type"].(string)
  326. if typeStr == "http" {
  327. request := header["request"].(map[string]any)
  328. requestPath, _ := request["path"].([]any)
  329. params["path"] = requestPath[0].(string)
  330. headers, _ := request["headers"].(map[string]any)
  331. params["host"] = searchHost(headers)
  332. params["headerType"] = "http"
  333. }
  334. case "kcp":
  335. kcp, _ := stream["kcpSettings"].(map[string]any)
  336. header, _ := kcp["header"].(map[string]any)
  337. params["headerType"] = header["type"].(string)
  338. params["seed"] = kcp["seed"].(string)
  339. case "ws":
  340. ws, _ := stream["wsSettings"].(map[string]any)
  341. params["path"] = ws["path"].(string)
  342. if host, ok := ws["host"].(string); ok && len(host) > 0 {
  343. params["host"] = host
  344. } else {
  345. headers, _ := ws["headers"].(map[string]any)
  346. params["host"] = searchHost(headers)
  347. }
  348. case "grpc":
  349. grpc, _ := stream["grpcSettings"].(map[string]any)
  350. params["serviceName"] = grpc["serviceName"].(string)
  351. params["authority"], _ = grpc["authority"].(string)
  352. if grpc["multiMode"].(bool) {
  353. params["mode"] = "multi"
  354. }
  355. case "httpupgrade":
  356. httpupgrade, _ := stream["httpupgradeSettings"].(map[string]any)
  357. params["path"] = httpupgrade["path"].(string)
  358. if host, ok := httpupgrade["host"].(string); ok && len(host) > 0 {
  359. params["host"] = host
  360. } else {
  361. headers, _ := httpupgrade["headers"].(map[string]any)
  362. params["host"] = searchHost(headers)
  363. }
  364. case "xhttp":
  365. xhttp, _ := stream["xhttpSettings"].(map[string]any)
  366. params["path"] = xhttp["path"].(string)
  367. if host, ok := xhttp["host"].(string); ok && len(host) > 0 {
  368. params["host"] = host
  369. } else {
  370. headers, _ := xhttp["headers"].(map[string]any)
  371. params["host"] = searchHost(headers)
  372. }
  373. params["mode"] = xhttp["mode"].(string)
  374. }
  375. security, _ := stream["security"].(string)
  376. if security == "tls" {
  377. params["security"] = "tls"
  378. tlsSetting, _ := stream["tlsSettings"].(map[string]any)
  379. alpns, _ := tlsSetting["alpn"].([]any)
  380. var alpn []string
  381. for _, a := range alpns {
  382. alpn = append(alpn, a.(string))
  383. }
  384. if len(alpn) > 0 {
  385. params["alpn"] = strings.Join(alpn, ",")
  386. }
  387. if sniValue, ok := searchKey(tlsSetting, "serverName"); ok {
  388. params["sni"], _ = sniValue.(string)
  389. }
  390. tlsSettings, _ := searchKey(tlsSetting, "settings")
  391. if tlsSetting != nil {
  392. if fpValue, ok := searchKey(tlsSettings, "fingerprint"); ok {
  393. params["fp"], _ = fpValue.(string)
  394. }
  395. if insecure, ok := searchKey(tlsSettings, "allowInsecure"); ok {
  396. if insecure.(bool) {
  397. params["allowInsecure"] = "1"
  398. }
  399. }
  400. }
  401. if streamNetwork == "tcp" && len(clients[clientIndex].Flow) > 0 {
  402. params["flow"] = clients[clientIndex].Flow
  403. }
  404. }
  405. if security == "reality" {
  406. params["security"] = "reality"
  407. realitySetting, _ := stream["realitySettings"].(map[string]any)
  408. realitySettings, _ := searchKey(realitySetting, "settings")
  409. if realitySetting != nil {
  410. if sniValue, ok := searchKey(realitySetting, "serverNames"); ok {
  411. sNames, _ := sniValue.([]any)
  412. params["sni"] = sNames[random.Num(len(sNames))].(string)
  413. }
  414. if pbkValue, ok := searchKey(realitySettings, "publicKey"); ok {
  415. params["pbk"], _ = pbkValue.(string)
  416. }
  417. if sidValue, ok := searchKey(realitySetting, "shortIds"); ok {
  418. shortIds, _ := sidValue.([]any)
  419. params["sid"] = shortIds[random.Num(len(shortIds))].(string)
  420. }
  421. if fpValue, ok := searchKey(realitySettings, "fingerprint"); ok {
  422. if fp, ok := fpValue.(string); ok && len(fp) > 0 {
  423. params["fp"] = fp
  424. }
  425. }
  426. if pqvValue, ok := searchKey(realitySettings, "mldsa65Verify"); ok {
  427. if pqv, ok := pqvValue.(string); ok && len(pqv) > 0 {
  428. params["pqv"] = pqv
  429. }
  430. }
  431. params["spx"] = "/" + random.Seq(15)
  432. }
  433. if streamNetwork == "tcp" && len(clients[clientIndex].Flow) > 0 {
  434. params["flow"] = clients[clientIndex].Flow
  435. }
  436. }
  437. if security != "tls" && security != "reality" {
  438. params["security"] = "none"
  439. }
  440. externalProxies, _ := stream["externalProxy"].([]any)
  441. if len(externalProxies) > 0 {
  442. links := ""
  443. for index, externalProxy := range externalProxies {
  444. ep, _ := externalProxy.(map[string]any)
  445. newSecurity, _ := ep["forceTls"].(string)
  446. dest, _ := ep["dest"].(string)
  447. port := int(ep["port"].(float64))
  448. link := fmt.Sprintf("vless://%s@%s:%d", uuid, dest, port)
  449. if newSecurity != "same" {
  450. params["security"] = newSecurity
  451. } else {
  452. params["security"] = security
  453. }
  454. url, _ := url.Parse(link)
  455. q := url.Query()
  456. for k, v := range params {
  457. if !(newSecurity == "none" && (k == "alpn" || k == "sni" || k == "fp" || k == "allowInsecure")) {
  458. q.Add(k, v)
  459. }
  460. }
  461. // Set the new query values on the URL
  462. url.RawQuery = q.Encode()
  463. url.Fragment = s.genRemark(inbound, email, ep["remark"].(string))
  464. if index > 0 {
  465. links += "\n"
  466. }
  467. links += url.String()
  468. }
  469. return links
  470. }
  471. link := fmt.Sprintf("vless://%s@%s:%d", uuid, address, port)
  472. url, _ := url.Parse(link)
  473. q := url.Query()
  474. for k, v := range params {
  475. q.Add(k, v)
  476. }
  477. // Set the new query values on the URL
  478. url.RawQuery = q.Encode()
  479. url.Fragment = s.genRemark(inbound, email, "")
  480. return url.String()
  481. }
  482. func (s *SubService) genTrojanLink(inbound *model.Inbound, email string) string {
  483. address := s.address
  484. if inbound.Protocol != model.Trojan {
  485. return ""
  486. }
  487. var stream map[string]any
  488. json.Unmarshal([]byte(inbound.StreamSettings), &stream)
  489. clients, _ := s.inboundService.GetClients(inbound)
  490. clientIndex := -1
  491. for i, client := range clients {
  492. if client.Email == email {
  493. clientIndex = i
  494. break
  495. }
  496. }
  497. password := clients[clientIndex].Password
  498. port := inbound.Port
  499. streamNetwork := stream["network"].(string)
  500. params := make(map[string]string)
  501. params["type"] = streamNetwork
  502. switch streamNetwork {
  503. case "tcp":
  504. tcp, _ := stream["tcpSettings"].(map[string]any)
  505. header, _ := tcp["header"].(map[string]any)
  506. typeStr, _ := header["type"].(string)
  507. if typeStr == "http" {
  508. request := header["request"].(map[string]any)
  509. requestPath, _ := request["path"].([]any)
  510. params["path"] = requestPath[0].(string)
  511. headers, _ := request["headers"].(map[string]any)
  512. params["host"] = searchHost(headers)
  513. params["headerType"] = "http"
  514. }
  515. case "kcp":
  516. kcp, _ := stream["kcpSettings"].(map[string]any)
  517. header, _ := kcp["header"].(map[string]any)
  518. params["headerType"] = header["type"].(string)
  519. params["seed"] = kcp["seed"].(string)
  520. case "ws":
  521. ws, _ := stream["wsSettings"].(map[string]any)
  522. params["path"] = ws["path"].(string)
  523. if host, ok := ws["host"].(string); ok && len(host) > 0 {
  524. params["host"] = host
  525. } else {
  526. headers, _ := ws["headers"].(map[string]any)
  527. params["host"] = searchHost(headers)
  528. }
  529. case "grpc":
  530. grpc, _ := stream["grpcSettings"].(map[string]any)
  531. params["serviceName"] = grpc["serviceName"].(string)
  532. params["authority"], _ = grpc["authority"].(string)
  533. if grpc["multiMode"].(bool) {
  534. params["mode"] = "multi"
  535. }
  536. case "httpupgrade":
  537. httpupgrade, _ := stream["httpupgradeSettings"].(map[string]any)
  538. params["path"] = httpupgrade["path"].(string)
  539. if host, ok := httpupgrade["host"].(string); ok && len(host) > 0 {
  540. params["host"] = host
  541. } else {
  542. headers, _ := httpupgrade["headers"].(map[string]any)
  543. params["host"] = searchHost(headers)
  544. }
  545. case "xhttp":
  546. xhttp, _ := stream["xhttpSettings"].(map[string]any)
  547. params["path"] = xhttp["path"].(string)
  548. if host, ok := xhttp["host"].(string); ok && len(host) > 0 {
  549. params["host"] = host
  550. } else {
  551. headers, _ := xhttp["headers"].(map[string]any)
  552. params["host"] = searchHost(headers)
  553. }
  554. params["mode"] = xhttp["mode"].(string)
  555. }
  556. security, _ := stream["security"].(string)
  557. if security == "tls" {
  558. params["security"] = "tls"
  559. tlsSetting, _ := stream["tlsSettings"].(map[string]any)
  560. alpns, _ := tlsSetting["alpn"].([]any)
  561. var alpn []string
  562. for _, a := range alpns {
  563. alpn = append(alpn, a.(string))
  564. }
  565. if len(alpn) > 0 {
  566. params["alpn"] = strings.Join(alpn, ",")
  567. }
  568. if sniValue, ok := searchKey(tlsSetting, "serverName"); ok {
  569. params["sni"], _ = sniValue.(string)
  570. }
  571. tlsSettings, _ := searchKey(tlsSetting, "settings")
  572. if tlsSetting != nil {
  573. if fpValue, ok := searchKey(tlsSettings, "fingerprint"); ok {
  574. params["fp"], _ = fpValue.(string)
  575. }
  576. if insecure, ok := searchKey(tlsSettings, "allowInsecure"); ok {
  577. if insecure.(bool) {
  578. params["allowInsecure"] = "1"
  579. }
  580. }
  581. }
  582. }
  583. if security == "reality" {
  584. params["security"] = "reality"
  585. realitySetting, _ := stream["realitySettings"].(map[string]any)
  586. realitySettings, _ := searchKey(realitySetting, "settings")
  587. if realitySetting != nil {
  588. if sniValue, ok := searchKey(realitySetting, "serverNames"); ok {
  589. sNames, _ := sniValue.([]any)
  590. params["sni"] = sNames[random.Num(len(sNames))].(string)
  591. }
  592. if pbkValue, ok := searchKey(realitySettings, "publicKey"); ok {
  593. params["pbk"], _ = pbkValue.(string)
  594. }
  595. if sidValue, ok := searchKey(realitySetting, "shortIds"); ok {
  596. shortIds, _ := sidValue.([]any)
  597. params["sid"] = shortIds[random.Num(len(shortIds))].(string)
  598. }
  599. if fpValue, ok := searchKey(realitySettings, "fingerprint"); ok {
  600. if fp, ok := fpValue.(string); ok && len(fp) > 0 {
  601. params["fp"] = fp
  602. }
  603. }
  604. if pqvValue, ok := searchKey(realitySettings, "mldsa65Verify"); ok {
  605. if pqv, ok := pqvValue.(string); ok && len(pqv) > 0 {
  606. params["pqv"] = pqv
  607. }
  608. }
  609. params["spx"] = "/" + random.Seq(15)
  610. }
  611. if streamNetwork == "tcp" && len(clients[clientIndex].Flow) > 0 {
  612. params["flow"] = clients[clientIndex].Flow
  613. }
  614. }
  615. if security != "tls" && security != "reality" {
  616. params["security"] = "none"
  617. }
  618. externalProxies, _ := stream["externalProxy"].([]any)
  619. if len(externalProxies) > 0 {
  620. links := ""
  621. for index, externalProxy := range externalProxies {
  622. ep, _ := externalProxy.(map[string]any)
  623. newSecurity, _ := ep["forceTls"].(string)
  624. dest, _ := ep["dest"].(string)
  625. port := int(ep["port"].(float64))
  626. link := fmt.Sprintf("trojan://%s@%s:%d", password, dest, port)
  627. if newSecurity != "same" {
  628. params["security"] = newSecurity
  629. } else {
  630. params["security"] = security
  631. }
  632. url, _ := url.Parse(link)
  633. q := url.Query()
  634. for k, v := range params {
  635. if !(newSecurity == "none" && (k == "alpn" || k == "sni" || k == "fp" || k == "allowInsecure")) {
  636. q.Add(k, v)
  637. }
  638. }
  639. // Set the new query values on the URL
  640. url.RawQuery = q.Encode()
  641. url.Fragment = s.genRemark(inbound, email, ep["remark"].(string))
  642. if index > 0 {
  643. links += "\n"
  644. }
  645. links += url.String()
  646. }
  647. return links
  648. }
  649. link := fmt.Sprintf("trojan://%s@%s:%d", password, address, port)
  650. url, _ := url.Parse(link)
  651. q := url.Query()
  652. for k, v := range params {
  653. q.Add(k, v)
  654. }
  655. // Set the new query values on the URL
  656. url.RawQuery = q.Encode()
  657. url.Fragment = s.genRemark(inbound, email, "")
  658. return url.String()
  659. }
  660. func (s *SubService) genShadowsocksLink(inbound *model.Inbound, email string) string {
  661. address := s.address
  662. if inbound.Protocol != model.Shadowsocks {
  663. return ""
  664. }
  665. var stream map[string]any
  666. json.Unmarshal([]byte(inbound.StreamSettings), &stream)
  667. clients, _ := s.inboundService.GetClients(inbound)
  668. var settings map[string]any
  669. json.Unmarshal([]byte(inbound.Settings), &settings)
  670. inboundPassword := settings["password"].(string)
  671. method := settings["method"].(string)
  672. clientIndex := -1
  673. for i, client := range clients {
  674. if client.Email == email {
  675. clientIndex = i
  676. break
  677. }
  678. }
  679. streamNetwork := stream["network"].(string)
  680. params := make(map[string]string)
  681. params["type"] = streamNetwork
  682. switch streamNetwork {
  683. case "tcp":
  684. tcp, _ := stream["tcpSettings"].(map[string]any)
  685. header, _ := tcp["header"].(map[string]any)
  686. typeStr, _ := header["type"].(string)
  687. if typeStr == "http" {
  688. request := header["request"].(map[string]any)
  689. requestPath, _ := request["path"].([]any)
  690. params["path"] = requestPath[0].(string)
  691. headers, _ := request["headers"].(map[string]any)
  692. params["host"] = searchHost(headers)
  693. params["headerType"] = "http"
  694. }
  695. case "kcp":
  696. kcp, _ := stream["kcpSettings"].(map[string]any)
  697. header, _ := kcp["header"].(map[string]any)
  698. params["headerType"] = header["type"].(string)
  699. params["seed"] = kcp["seed"].(string)
  700. case "ws":
  701. ws, _ := stream["wsSettings"].(map[string]any)
  702. params["path"] = ws["path"].(string)
  703. if host, ok := ws["host"].(string); ok && len(host) > 0 {
  704. params["host"] = host
  705. } else {
  706. headers, _ := ws["headers"].(map[string]any)
  707. params["host"] = searchHost(headers)
  708. }
  709. case "grpc":
  710. grpc, _ := stream["grpcSettings"].(map[string]any)
  711. params["serviceName"] = grpc["serviceName"].(string)
  712. params["authority"], _ = grpc["authority"].(string)
  713. if grpc["multiMode"].(bool) {
  714. params["mode"] = "multi"
  715. }
  716. case "httpupgrade":
  717. httpupgrade, _ := stream["httpupgradeSettings"].(map[string]any)
  718. params["path"] = httpupgrade["path"].(string)
  719. if host, ok := httpupgrade["host"].(string); ok && len(host) > 0 {
  720. params["host"] = host
  721. } else {
  722. headers, _ := httpupgrade["headers"].(map[string]any)
  723. params["host"] = searchHost(headers)
  724. }
  725. case "xhttp":
  726. xhttp, _ := stream["xhttpSettings"].(map[string]any)
  727. params["path"] = xhttp["path"].(string)
  728. if host, ok := xhttp["host"].(string); ok && len(host) > 0 {
  729. params["host"] = host
  730. } else {
  731. headers, _ := xhttp["headers"].(map[string]any)
  732. params["host"] = searchHost(headers)
  733. }
  734. params["mode"] = xhttp["mode"].(string)
  735. }
  736. security, _ := stream["security"].(string)
  737. if security == "tls" {
  738. params["security"] = "tls"
  739. tlsSetting, _ := stream["tlsSettings"].(map[string]any)
  740. alpns, _ := tlsSetting["alpn"].([]any)
  741. var alpn []string
  742. for _, a := range alpns {
  743. alpn = append(alpn, a.(string))
  744. }
  745. if len(alpn) > 0 {
  746. params["alpn"] = strings.Join(alpn, ",")
  747. }
  748. if sniValue, ok := searchKey(tlsSetting, "serverName"); ok {
  749. params["sni"], _ = sniValue.(string)
  750. }
  751. tlsSettings, _ := searchKey(tlsSetting, "settings")
  752. if tlsSetting != nil {
  753. if fpValue, ok := searchKey(tlsSettings, "fingerprint"); ok {
  754. params["fp"], _ = fpValue.(string)
  755. }
  756. if insecure, ok := searchKey(tlsSettings, "allowInsecure"); ok {
  757. if insecure.(bool) {
  758. params["allowInsecure"] = "1"
  759. }
  760. }
  761. }
  762. }
  763. encPart := fmt.Sprintf("%s:%s", method, clients[clientIndex].Password)
  764. if method[0] == '2' {
  765. encPart = fmt.Sprintf("%s:%s:%s", method, inboundPassword, clients[clientIndex].Password)
  766. }
  767. externalProxies, _ := stream["externalProxy"].([]any)
  768. if len(externalProxies) > 0 {
  769. links := ""
  770. for index, externalProxy := range externalProxies {
  771. ep, _ := externalProxy.(map[string]any)
  772. newSecurity, _ := ep["forceTls"].(string)
  773. dest, _ := ep["dest"].(string)
  774. port := int(ep["port"].(float64))
  775. link := fmt.Sprintf("ss://%s@%s:%d", base64.StdEncoding.EncodeToString([]byte(encPart)), dest, port)
  776. if newSecurity != "same" {
  777. params["security"] = newSecurity
  778. } else {
  779. params["security"] = security
  780. }
  781. url, _ := url.Parse(link)
  782. q := url.Query()
  783. for k, v := range params {
  784. if !(newSecurity == "none" && (k == "alpn" || k == "sni" || k == "fp" || k == "allowInsecure")) {
  785. q.Add(k, v)
  786. }
  787. }
  788. // Set the new query values on the URL
  789. url.RawQuery = q.Encode()
  790. url.Fragment = s.genRemark(inbound, email, ep["remark"].(string))
  791. if index > 0 {
  792. links += "\n"
  793. }
  794. links += url.String()
  795. }
  796. return links
  797. }
  798. link := fmt.Sprintf("ss://%s@%s:%d", base64.StdEncoding.EncodeToString([]byte(encPart)), address, inbound.Port)
  799. url, _ := url.Parse(link)
  800. q := url.Query()
  801. for k, v := range params {
  802. q.Add(k, v)
  803. }
  804. // Set the new query values on the URL
  805. url.RawQuery = q.Encode()
  806. url.Fragment = s.genRemark(inbound, email, "")
  807. return url.String()
  808. }
  809. func (s *SubService) genRemark(inbound *model.Inbound, email string, extra string) string {
  810. separationChar := string(s.remarkModel[0])
  811. orderChars := s.remarkModel[1:]
  812. orders := map[byte]string{
  813. 'i': "",
  814. 'e': "",
  815. 'o': "",
  816. }
  817. if len(email) > 0 {
  818. orders['e'] = email
  819. }
  820. if len(inbound.Remark) > 0 {
  821. orders['i'] = inbound.Remark
  822. }
  823. if len(extra) > 0 {
  824. orders['o'] = extra
  825. }
  826. var remark []string
  827. for i := 0; i < len(orderChars); i++ {
  828. char := orderChars[i]
  829. order, exists := orders[char]
  830. if exists && order != "" {
  831. remark = append(remark, order)
  832. }
  833. }
  834. if s.showInfo {
  835. statsExist := false
  836. var stats xray.ClientTraffic
  837. for _, clientStat := range inbound.ClientStats {
  838. if clientStat.Email == email {
  839. stats = clientStat
  840. statsExist = true
  841. break
  842. }
  843. }
  844. // Get remained days
  845. if statsExist {
  846. if !stats.Enable {
  847. return fmt.Sprintf("⛔️N/A%s%s", separationChar, strings.Join(remark, separationChar))
  848. }
  849. if vol := stats.Total - (stats.Up + stats.Down); vol > 0 {
  850. remark = append(remark, fmt.Sprintf("%s%s", common.FormatTraffic(vol), "📊"))
  851. }
  852. now := time.Now().Unix()
  853. switch exp := stats.ExpiryTime / 1000; {
  854. case exp > 0:
  855. remainingSeconds := exp - now
  856. days := remainingSeconds / 86400
  857. hours := (remainingSeconds % 86400) / 3600
  858. minutes := (remainingSeconds % 3600) / 60
  859. if days > 0 {
  860. if hours > 0 {
  861. remark = append(remark, fmt.Sprintf("%dD,%dH⏳", days, hours))
  862. } else {
  863. remark = append(remark, fmt.Sprintf("%dD⏳", days))
  864. }
  865. } else if hours > 0 {
  866. remark = append(remark, fmt.Sprintf("%dH⏳", hours))
  867. } else {
  868. remark = append(remark, fmt.Sprintf("%dM⏳", minutes))
  869. }
  870. case exp < 0:
  871. days := exp / -86400
  872. hours := (exp % -86400) / 3600
  873. minutes := (exp % -3600) / 60
  874. if days > 0 {
  875. if hours > 0 {
  876. remark = append(remark, fmt.Sprintf("%dD,%dH⏳", days, hours))
  877. } else {
  878. remark = append(remark, fmt.Sprintf("%dD⏳", days))
  879. }
  880. } else if hours > 0 {
  881. remark = append(remark, fmt.Sprintf("%dH⏳", hours))
  882. } else {
  883. remark = append(remark, fmt.Sprintf("%dM⏳", minutes))
  884. }
  885. }
  886. }
  887. }
  888. return strings.Join(remark, separationChar)
  889. }
  890. func searchKey(data any, key string) (any, bool) {
  891. switch val := data.(type) {
  892. case map[string]any:
  893. for k, v := range val {
  894. if k == key {
  895. return v, true
  896. }
  897. if result, ok := searchKey(v, key); ok {
  898. return result, true
  899. }
  900. }
  901. case []any:
  902. for _, v := range val {
  903. if result, ok := searchKey(v, key); ok {
  904. return result, true
  905. }
  906. }
  907. }
  908. return nil, false
  909. }
  910. func searchHost(headers any) string {
  911. data, _ := headers.(map[string]any)
  912. for k, v := range data {
  913. if strings.EqualFold(k, "host") {
  914. switch v.(type) {
  915. case []any:
  916. hosts, _ := v.([]any)
  917. if len(hosts) > 0 {
  918. return hosts[0].(string)
  919. } else {
  920. return ""
  921. }
  922. case any:
  923. return v.(string)
  924. }
  925. }
  926. }
  927. return ""
  928. }
  929. // PageData is a view model for subpage.html
  930. // PageData contains data for rendering the subscription information page.
  931. type PageData struct {
  932. Host string
  933. BasePath string
  934. SId string
  935. Download string
  936. Upload string
  937. Total string
  938. Used string
  939. Remained string
  940. Expire int64
  941. LastOnline int64
  942. Datepicker string
  943. DownloadByte int64
  944. UploadByte int64
  945. TotalByte int64
  946. SubUrl string
  947. SubJsonUrl string
  948. Result []string
  949. }
  950. // ResolveRequest extracts scheme and host info from request/headers consistently.
  951. // ResolveRequest extracts scheme, host, and header information from an HTTP request.
  952. func (s *SubService) ResolveRequest(c *gin.Context) (scheme string, host string, hostWithPort string, hostHeader string) {
  953. // scheme
  954. scheme = "http"
  955. if c.Request.TLS != nil || strings.EqualFold(c.GetHeader("X-Forwarded-Proto"), "https") {
  956. scheme = "https"
  957. }
  958. // base host (no port)
  959. if h, err := getHostFromXFH(c.GetHeader("X-Forwarded-Host")); err == nil && h != "" {
  960. host = h
  961. }
  962. if host == "" {
  963. host = c.GetHeader("X-Real-IP")
  964. }
  965. if host == "" {
  966. var err error
  967. host, _, err = net.SplitHostPort(c.Request.Host)
  968. if err != nil {
  969. host = c.Request.Host
  970. }
  971. }
  972. // host:port for URLs
  973. hostWithPort = c.GetHeader("X-Forwarded-Host")
  974. if hostWithPort == "" {
  975. hostWithPort = c.Request.Host
  976. }
  977. if hostWithPort == "" {
  978. hostWithPort = host
  979. }
  980. // header display host
  981. hostHeader = c.GetHeader("X-Forwarded-Host")
  982. if hostHeader == "" {
  983. hostHeader = c.GetHeader("X-Real-IP")
  984. }
  985. if hostHeader == "" {
  986. hostHeader = host
  987. }
  988. return
  989. }
  990. // BuildURLs constructs absolute subscription and json URLs.
  991. // BuildURLs constructs subscription and JSON subscription URLs for a given subscription ID.
  992. func (s *SubService) BuildURLs(scheme, hostWithPort, subPath, subJsonPath, subId string) (subURL, subJsonURL string) {
  993. if strings.HasSuffix(subPath, "/") {
  994. subURL = scheme + "://" + hostWithPort + subPath + subId
  995. } else {
  996. subURL = scheme + "://" + hostWithPort + strings.TrimRight(subPath, "/") + "/" + subId
  997. }
  998. if strings.HasSuffix(subJsonPath, "/") {
  999. subJsonURL = scheme + "://" + hostWithPort + subJsonPath + subId
  1000. } else {
  1001. subJsonURL = scheme + "://" + hostWithPort + strings.TrimRight(subJsonPath, "/") + "/" + subId
  1002. }
  1003. return
  1004. }
  1005. // BuildPageData parses header and prepares the template view model.
  1006. // BuildPageData constructs page data for rendering the subscription information page.
  1007. func (s *SubService) BuildPageData(subId string, hostHeader string, traffic xray.ClientTraffic, lastOnline int64, subs []string, subURL, subJsonURL string) PageData {
  1008. download := common.FormatTraffic(traffic.Down)
  1009. upload := common.FormatTraffic(traffic.Up)
  1010. total := "∞"
  1011. used := common.FormatTraffic(traffic.Up + traffic.Down)
  1012. remained := ""
  1013. if traffic.Total > 0 {
  1014. total = common.FormatTraffic(traffic.Total)
  1015. left := traffic.Total - (traffic.Up + traffic.Down)
  1016. if left < 0 {
  1017. left = 0
  1018. }
  1019. remained = common.FormatTraffic(left)
  1020. }
  1021. datepicker := s.datepicker
  1022. if datepicker == "" {
  1023. datepicker = "gregorian"
  1024. }
  1025. return PageData{
  1026. Host: hostHeader,
  1027. BasePath: "/", // kept as "/"; templates now use context base_path injected from router
  1028. SId: subId,
  1029. Download: download,
  1030. Upload: upload,
  1031. Total: total,
  1032. Used: used,
  1033. Remained: remained,
  1034. Expire: traffic.ExpiryTime / 1000,
  1035. LastOnline: lastOnline,
  1036. Datepicker: datepicker,
  1037. DownloadByte: traffic.Down,
  1038. UploadByte: traffic.Up,
  1039. TotalByte: traffic.Total,
  1040. SubUrl: subURL,
  1041. SubJsonUrl: subJsonURL,
  1042. Result: subs,
  1043. }
  1044. }
  1045. func getHostFromXFH(s string) (string, error) {
  1046. if strings.Contains(s, ":") {
  1047. realHost, _, err := net.SplitHostPort(s)
  1048. if err != nil {
  1049. return "", err
  1050. }
  1051. return realHost, nil
  1052. }
  1053. return s, nil
  1054. }