subService.go 32 KB

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