1
0

subService.go 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199
  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. var address string
  167. if inbound.Listen == "" || inbound.Listen == "0.0.0.0" || inbound.Listen == "::" || inbound.Listen == "::0" {
  168. address = s.address
  169. } else {
  170. address = inbound.Listen
  171. }
  172. obj := map[string]any{
  173. "v": "2",
  174. "add": address,
  175. "port": inbound.Port,
  176. "type": "none",
  177. }
  178. var stream map[string]any
  179. json.Unmarshal([]byte(inbound.StreamSettings), &stream)
  180. network, _ := stream["network"].(string)
  181. obj["net"] = network
  182. switch network {
  183. case "tcp":
  184. tcp, _ := stream["tcpSettings"].(map[string]any)
  185. header, _ := tcp["header"].(map[string]any)
  186. typeStr, _ := header["type"].(string)
  187. obj["type"] = typeStr
  188. if typeStr == "http" {
  189. request := header["request"].(map[string]any)
  190. requestPath, _ := request["path"].([]any)
  191. obj["path"] = requestPath[0].(string)
  192. headers, _ := request["headers"].(map[string]any)
  193. obj["host"] = searchHost(headers)
  194. }
  195. case "kcp":
  196. kcp, _ := stream["kcpSettings"].(map[string]any)
  197. header, _ := kcp["header"].(map[string]any)
  198. obj["type"], _ = header["type"].(string)
  199. obj["path"], _ = kcp["seed"].(string)
  200. case "ws":
  201. ws, _ := stream["wsSettings"].(map[string]any)
  202. obj["path"] = ws["path"].(string)
  203. if host, ok := ws["host"].(string); ok && len(host) > 0 {
  204. obj["host"] = host
  205. } else {
  206. headers, _ := ws["headers"].(map[string]any)
  207. obj["host"] = searchHost(headers)
  208. }
  209. case "grpc":
  210. grpc, _ := stream["grpcSettings"].(map[string]any)
  211. obj["path"] = grpc["serviceName"].(string)
  212. obj["authority"] = grpc["authority"].(string)
  213. if grpc["multiMode"].(bool) {
  214. obj["type"] = "multi"
  215. }
  216. case "httpupgrade":
  217. httpupgrade, _ := stream["httpupgradeSettings"].(map[string]any)
  218. obj["path"] = httpupgrade["path"].(string)
  219. if host, ok := httpupgrade["host"].(string); ok && len(host) > 0 {
  220. obj["host"] = host
  221. } else {
  222. headers, _ := httpupgrade["headers"].(map[string]any)
  223. obj["host"] = searchHost(headers)
  224. }
  225. case "xhttp":
  226. xhttp, _ := stream["xhttpSettings"].(map[string]any)
  227. obj["path"] = xhttp["path"].(string)
  228. if host, ok := xhttp["host"].(string); ok && len(host) > 0 {
  229. obj["host"] = host
  230. } else {
  231. headers, _ := xhttp["headers"].(map[string]any)
  232. obj["host"] = searchHost(headers)
  233. }
  234. obj["mode"] = xhttp["mode"].(string)
  235. }
  236. security, _ := stream["security"].(string)
  237. obj["tls"] = security
  238. if security == "tls" {
  239. tlsSetting, _ := stream["tlsSettings"].(map[string]any)
  240. alpns, _ := tlsSetting["alpn"].([]any)
  241. if len(alpns) > 0 {
  242. var alpn []string
  243. for _, a := range alpns {
  244. alpn = append(alpn, a.(string))
  245. }
  246. obj["alpn"] = strings.Join(alpn, ",")
  247. }
  248. if sniValue, ok := searchKey(tlsSetting, "serverName"); ok {
  249. obj["sni"], _ = sniValue.(string)
  250. }
  251. tlsSettings, _ := searchKey(tlsSetting, "settings")
  252. if tlsSetting != nil {
  253. if fpValue, ok := searchKey(tlsSettings, "fingerprint"); ok {
  254. obj["fp"], _ = fpValue.(string)
  255. }
  256. }
  257. }
  258. clients, _ := s.inboundService.GetClients(inbound)
  259. clientIndex := -1
  260. for i, client := range clients {
  261. if client.Email == email {
  262. clientIndex = i
  263. break
  264. }
  265. }
  266. obj["id"] = clients[clientIndex].ID
  267. obj["scy"] = clients[clientIndex].Security
  268. externalProxies, _ := stream["externalProxy"].([]any)
  269. if len(externalProxies) > 0 {
  270. links := ""
  271. for index, externalProxy := range externalProxies {
  272. ep, _ := externalProxy.(map[string]any)
  273. newSecurity, _ := ep["forceTls"].(string)
  274. newObj := map[string]any{}
  275. for key, value := range obj {
  276. if !(newSecurity == "none" && (key == "alpn" || key == "sni" || key == "fp")) {
  277. newObj[key] = value
  278. }
  279. }
  280. newObj["ps"] = s.genRemark(inbound, email, ep["remark"].(string))
  281. newObj["add"] = ep["dest"].(string)
  282. newObj["port"] = int(ep["port"].(float64))
  283. if newSecurity != "same" {
  284. newObj["tls"] = newSecurity
  285. }
  286. if index > 0 {
  287. links += "\n"
  288. }
  289. jsonStr, _ := json.MarshalIndent(newObj, "", " ")
  290. links += "vmess://" + base64.StdEncoding.EncodeToString(jsonStr)
  291. }
  292. return links
  293. }
  294. obj["ps"] = s.genRemark(inbound, email, "")
  295. jsonStr, _ := json.MarshalIndent(obj, "", " ")
  296. return "vmess://" + base64.StdEncoding.EncodeToString(jsonStr)
  297. }
  298. func (s *SubService) genVlessLink(inbound *model.Inbound, email string) string {
  299. var address string
  300. if inbound.Listen == "" || inbound.Listen == "0.0.0.0" || inbound.Listen == "::" || inbound.Listen == "::0" {
  301. address = s.address
  302. } else {
  303. address = inbound.Listen
  304. }
  305. if inbound.Protocol != model.VLESS {
  306. return ""
  307. }
  308. var stream map[string]any
  309. json.Unmarshal([]byte(inbound.StreamSettings), &stream)
  310. clients, _ := s.inboundService.GetClients(inbound)
  311. clientIndex := -1
  312. for i, client := range clients {
  313. if client.Email == email {
  314. clientIndex = i
  315. break
  316. }
  317. }
  318. uuid := clients[clientIndex].ID
  319. port := inbound.Port
  320. streamNetwork := stream["network"].(string)
  321. params := make(map[string]string)
  322. params["type"] = streamNetwork
  323. // Add encryption parameter for VLESS from inbound settings
  324. var settings map[string]any
  325. json.Unmarshal([]byte(inbound.Settings), &settings)
  326. if encryption, ok := settings["encryption"].(string); ok {
  327. params["encryption"] = encryption
  328. }
  329. switch streamNetwork {
  330. case "tcp":
  331. tcp, _ := stream["tcpSettings"].(map[string]any)
  332. header, _ := tcp["header"].(map[string]any)
  333. typeStr, _ := header["type"].(string)
  334. if typeStr == "http" {
  335. request := header["request"].(map[string]any)
  336. requestPath, _ := request["path"].([]any)
  337. params["path"] = requestPath[0].(string)
  338. headers, _ := request["headers"].(map[string]any)
  339. params["host"] = searchHost(headers)
  340. params["headerType"] = "http"
  341. }
  342. case "kcp":
  343. kcp, _ := stream["kcpSettings"].(map[string]any)
  344. header, _ := kcp["header"].(map[string]any)
  345. params["headerType"] = header["type"].(string)
  346. params["seed"] = kcp["seed"].(string)
  347. case "ws":
  348. ws, _ := stream["wsSettings"].(map[string]any)
  349. params["path"] = ws["path"].(string)
  350. if host, ok := ws["host"].(string); ok && len(host) > 0 {
  351. params["host"] = host
  352. } else {
  353. headers, _ := ws["headers"].(map[string]any)
  354. params["host"] = searchHost(headers)
  355. }
  356. case "grpc":
  357. grpc, _ := stream["grpcSettings"].(map[string]any)
  358. params["serviceName"] = grpc["serviceName"].(string)
  359. params["authority"], _ = grpc["authority"].(string)
  360. if grpc["multiMode"].(bool) {
  361. params["mode"] = "multi"
  362. }
  363. case "httpupgrade":
  364. httpupgrade, _ := stream["httpupgradeSettings"].(map[string]any)
  365. params["path"] = httpupgrade["path"].(string)
  366. if host, ok := httpupgrade["host"].(string); ok && len(host) > 0 {
  367. params["host"] = host
  368. } else {
  369. headers, _ := httpupgrade["headers"].(map[string]any)
  370. params["host"] = searchHost(headers)
  371. }
  372. case "xhttp":
  373. xhttp, _ := stream["xhttpSettings"].(map[string]any)
  374. params["path"] = xhttp["path"].(string)
  375. if host, ok := xhttp["host"].(string); ok && len(host) > 0 {
  376. params["host"] = host
  377. } else {
  378. headers, _ := xhttp["headers"].(map[string]any)
  379. params["host"] = searchHost(headers)
  380. }
  381. params["mode"] = xhttp["mode"].(string)
  382. }
  383. security, _ := stream["security"].(string)
  384. if security == "tls" {
  385. params["security"] = "tls"
  386. tlsSetting, _ := stream["tlsSettings"].(map[string]any)
  387. alpns, _ := tlsSetting["alpn"].([]any)
  388. var alpn []string
  389. for _, a := range alpns {
  390. alpn = append(alpn, a.(string))
  391. }
  392. if len(alpn) > 0 {
  393. params["alpn"] = strings.Join(alpn, ",")
  394. }
  395. if sniValue, ok := searchKey(tlsSetting, "serverName"); ok {
  396. params["sni"], _ = sniValue.(string)
  397. }
  398. tlsSettings, _ := searchKey(tlsSetting, "settings")
  399. if tlsSetting != nil {
  400. if fpValue, ok := searchKey(tlsSettings, "fingerprint"); ok {
  401. params["fp"], _ = fpValue.(string)
  402. }
  403. }
  404. if streamNetwork == "tcp" && len(clients[clientIndex].Flow) > 0 {
  405. params["flow"] = clients[clientIndex].Flow
  406. }
  407. }
  408. if security == "reality" {
  409. params["security"] = "reality"
  410. realitySetting, _ := stream["realitySettings"].(map[string]any)
  411. realitySettings, _ := searchKey(realitySetting, "settings")
  412. if realitySetting != nil {
  413. if sniValue, ok := searchKey(realitySetting, "serverNames"); ok {
  414. sNames, _ := sniValue.([]any)
  415. params["sni"] = sNames[random.Num(len(sNames))].(string)
  416. }
  417. if pbkValue, ok := searchKey(realitySettings, "publicKey"); ok {
  418. params["pbk"], _ = pbkValue.(string)
  419. }
  420. if sidValue, ok := searchKey(realitySetting, "shortIds"); ok {
  421. shortIds, _ := sidValue.([]any)
  422. params["sid"] = shortIds[random.Num(len(shortIds))].(string)
  423. }
  424. if fpValue, ok := searchKey(realitySettings, "fingerprint"); ok {
  425. if fp, ok := fpValue.(string); ok && len(fp) > 0 {
  426. params["fp"] = fp
  427. }
  428. }
  429. if pqvValue, ok := searchKey(realitySettings, "mldsa65Verify"); ok {
  430. if pqv, ok := pqvValue.(string); ok && len(pqv) > 0 {
  431. params["pqv"] = pqv
  432. }
  433. }
  434. params["spx"] = "/" + random.Seq(15)
  435. }
  436. if streamNetwork == "tcp" && len(clients[clientIndex].Flow) > 0 {
  437. params["flow"] = clients[clientIndex].Flow
  438. }
  439. }
  440. if security != "tls" && security != "reality" {
  441. params["security"] = "none"
  442. }
  443. externalProxies, _ := stream["externalProxy"].([]any)
  444. if len(externalProxies) > 0 {
  445. links := make([]string, 0, len(externalProxies))
  446. for _, externalProxy := range externalProxies {
  447. ep, _ := externalProxy.(map[string]any)
  448. newSecurity, _ := ep["forceTls"].(string)
  449. dest, _ := ep["dest"].(string)
  450. port := int(ep["port"].(float64))
  451. link := fmt.Sprintf("vless://%s@%s:%d", uuid, dest, port)
  452. if newSecurity != "same" {
  453. params["security"] = newSecurity
  454. } else {
  455. params["security"] = security
  456. }
  457. url, _ := url.Parse(link)
  458. q := url.Query()
  459. for k, v := range params {
  460. if !(newSecurity == "none" && (k == "alpn" || k == "sni" || k == "fp")) {
  461. q.Add(k, v)
  462. }
  463. }
  464. // Set the new query values on the URL
  465. url.RawQuery = q.Encode()
  466. url.Fragment = s.genRemark(inbound, email, ep["remark"].(string))
  467. links = append(links, url.String())
  468. }
  469. return strings.Join(links, "\n")
  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. var address string
  484. if inbound.Listen == "" || inbound.Listen == "0.0.0.0" || inbound.Listen == "::" || inbound.Listen == "::0" {
  485. address = s.address
  486. } else {
  487. address = inbound.Listen
  488. }
  489. if inbound.Protocol != model.Trojan {
  490. return ""
  491. }
  492. var stream map[string]any
  493. json.Unmarshal([]byte(inbound.StreamSettings), &stream)
  494. clients, _ := s.inboundService.GetClients(inbound)
  495. clientIndex := -1
  496. for i, client := range clients {
  497. if client.Email == email {
  498. clientIndex = i
  499. break
  500. }
  501. }
  502. password := clients[clientIndex].Password
  503. port := inbound.Port
  504. streamNetwork := stream["network"].(string)
  505. params := make(map[string]string)
  506. params["type"] = streamNetwork
  507. switch streamNetwork {
  508. case "tcp":
  509. tcp, _ := stream["tcpSettings"].(map[string]any)
  510. header, _ := tcp["header"].(map[string]any)
  511. typeStr, _ := header["type"].(string)
  512. if typeStr == "http" {
  513. request := header["request"].(map[string]any)
  514. requestPath, _ := request["path"].([]any)
  515. params["path"] = requestPath[0].(string)
  516. headers, _ := request["headers"].(map[string]any)
  517. params["host"] = searchHost(headers)
  518. params["headerType"] = "http"
  519. }
  520. case "kcp":
  521. kcp, _ := stream["kcpSettings"].(map[string]any)
  522. header, _ := kcp["header"].(map[string]any)
  523. params["headerType"] = header["type"].(string)
  524. params["seed"] = kcp["seed"].(string)
  525. case "ws":
  526. ws, _ := stream["wsSettings"].(map[string]any)
  527. params["path"] = ws["path"].(string)
  528. if host, ok := ws["host"].(string); ok && len(host) > 0 {
  529. params["host"] = host
  530. } else {
  531. headers, _ := ws["headers"].(map[string]any)
  532. params["host"] = searchHost(headers)
  533. }
  534. case "grpc":
  535. grpc, _ := stream["grpcSettings"].(map[string]any)
  536. params["serviceName"] = grpc["serviceName"].(string)
  537. params["authority"], _ = grpc["authority"].(string)
  538. if grpc["multiMode"].(bool) {
  539. params["mode"] = "multi"
  540. }
  541. case "httpupgrade":
  542. httpupgrade, _ := stream["httpupgradeSettings"].(map[string]any)
  543. params["path"] = httpupgrade["path"].(string)
  544. if host, ok := httpupgrade["host"].(string); ok && len(host) > 0 {
  545. params["host"] = host
  546. } else {
  547. headers, _ := httpupgrade["headers"].(map[string]any)
  548. params["host"] = searchHost(headers)
  549. }
  550. case "xhttp":
  551. xhttp, _ := stream["xhttpSettings"].(map[string]any)
  552. params["path"] = xhttp["path"].(string)
  553. if host, ok := xhttp["host"].(string); ok && len(host) > 0 {
  554. params["host"] = host
  555. } else {
  556. headers, _ := xhttp["headers"].(map[string]any)
  557. params["host"] = searchHost(headers)
  558. }
  559. params["mode"] = xhttp["mode"].(string)
  560. }
  561. security, _ := stream["security"].(string)
  562. if security == "tls" {
  563. params["security"] = "tls"
  564. tlsSetting, _ := stream["tlsSettings"].(map[string]any)
  565. alpns, _ := tlsSetting["alpn"].([]any)
  566. var alpn []string
  567. for _, a := range alpns {
  568. alpn = append(alpn, a.(string))
  569. }
  570. if len(alpn) > 0 {
  571. params["alpn"] = strings.Join(alpn, ",")
  572. }
  573. if sniValue, ok := searchKey(tlsSetting, "serverName"); ok {
  574. params["sni"], _ = sniValue.(string)
  575. }
  576. tlsSettings, _ := searchKey(tlsSetting, "settings")
  577. if tlsSetting != nil {
  578. if fpValue, ok := searchKey(tlsSettings, "fingerprint"); ok {
  579. params["fp"], _ = fpValue.(string)
  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")) {
  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. var address string
  662. if inbound.Listen == "" || inbound.Listen == "0.0.0.0" || inbound.Listen == "::" || inbound.Listen == "::0" {
  663. address = s.address
  664. } else {
  665. address = inbound.Listen
  666. }
  667. if inbound.Protocol != model.Shadowsocks {
  668. return ""
  669. }
  670. var stream map[string]any
  671. json.Unmarshal([]byte(inbound.StreamSettings), &stream)
  672. clients, _ := s.inboundService.GetClients(inbound)
  673. var settings map[string]any
  674. json.Unmarshal([]byte(inbound.Settings), &settings)
  675. inboundPassword := settings["password"].(string)
  676. method := settings["method"].(string)
  677. clientIndex := -1
  678. for i, client := range clients {
  679. if client.Email == email {
  680. clientIndex = i
  681. break
  682. }
  683. }
  684. streamNetwork := stream["network"].(string)
  685. params := make(map[string]string)
  686. params["type"] = streamNetwork
  687. switch streamNetwork {
  688. case "tcp":
  689. tcp, _ := stream["tcpSettings"].(map[string]any)
  690. header, _ := tcp["header"].(map[string]any)
  691. typeStr, _ := header["type"].(string)
  692. if typeStr == "http" {
  693. request := header["request"].(map[string]any)
  694. requestPath, _ := request["path"].([]any)
  695. params["path"] = requestPath[0].(string)
  696. headers, _ := request["headers"].(map[string]any)
  697. params["host"] = searchHost(headers)
  698. params["headerType"] = "http"
  699. }
  700. case "kcp":
  701. kcp, _ := stream["kcpSettings"].(map[string]any)
  702. header, _ := kcp["header"].(map[string]any)
  703. params["headerType"] = header["type"].(string)
  704. params["seed"] = kcp["seed"].(string)
  705. case "ws":
  706. ws, _ := stream["wsSettings"].(map[string]any)
  707. params["path"] = ws["path"].(string)
  708. if host, ok := ws["host"].(string); ok && len(host) > 0 {
  709. params["host"] = host
  710. } else {
  711. headers, _ := ws["headers"].(map[string]any)
  712. params["host"] = searchHost(headers)
  713. }
  714. case "grpc":
  715. grpc, _ := stream["grpcSettings"].(map[string]any)
  716. params["serviceName"] = grpc["serviceName"].(string)
  717. params["authority"], _ = grpc["authority"].(string)
  718. if grpc["multiMode"].(bool) {
  719. params["mode"] = "multi"
  720. }
  721. case "httpupgrade":
  722. httpupgrade, _ := stream["httpupgradeSettings"].(map[string]any)
  723. params["path"] = httpupgrade["path"].(string)
  724. if host, ok := httpupgrade["host"].(string); ok && len(host) > 0 {
  725. params["host"] = host
  726. } else {
  727. headers, _ := httpupgrade["headers"].(map[string]any)
  728. params["host"] = searchHost(headers)
  729. }
  730. case "xhttp":
  731. xhttp, _ := stream["xhttpSettings"].(map[string]any)
  732. params["path"] = xhttp["path"].(string)
  733. if host, ok := xhttp["host"].(string); ok && len(host) > 0 {
  734. params["host"] = host
  735. } else {
  736. headers, _ := xhttp["headers"].(map[string]any)
  737. params["host"] = searchHost(headers)
  738. }
  739. params["mode"] = xhttp["mode"].(string)
  740. }
  741. security, _ := stream["security"].(string)
  742. if security == "tls" {
  743. params["security"] = "tls"
  744. tlsSetting, _ := stream["tlsSettings"].(map[string]any)
  745. alpns, _ := tlsSetting["alpn"].([]any)
  746. var alpn []string
  747. for _, a := range alpns {
  748. alpn = append(alpn, a.(string))
  749. }
  750. if len(alpn) > 0 {
  751. params["alpn"] = strings.Join(alpn, ",")
  752. }
  753. if sniValue, ok := searchKey(tlsSetting, "serverName"); ok {
  754. params["sni"], _ = sniValue.(string)
  755. }
  756. tlsSettings, _ := searchKey(tlsSetting, "settings")
  757. if tlsSetting != nil {
  758. if fpValue, ok := searchKey(tlsSettings, "fingerprint"); ok {
  759. params["fp"], _ = fpValue.(string)
  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")) {
  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 subscription URLs for a given subscription ID.
  991. // It prioritizes configured URIs, then individual settings, and finally falls back to request-derived components.
  992. func (s *SubService) BuildURLs(scheme, hostWithPort, subPath, subJsonPath, subId string) (subURL, subJsonURL string) {
  993. // Input validation
  994. if subId == "" {
  995. return "", ""
  996. }
  997. // Get configured URIs first (highest priority)
  998. configuredSubURI, _ := s.settingService.GetSubURI()
  999. configuredSubJsonURI, _ := s.settingService.GetSubJsonURI()
  1000. // Determine base scheme and host (cached to avoid duplicate calls)
  1001. var baseScheme, baseHostWithPort string
  1002. if configuredSubURI == "" || configuredSubJsonURI == "" {
  1003. baseScheme, baseHostWithPort = s.getBaseSchemeAndHost(scheme, hostWithPort)
  1004. }
  1005. // Build subscription URL
  1006. subURL = s.buildSingleURL(configuredSubURI, baseScheme, baseHostWithPort, subPath, subId)
  1007. // Build JSON subscription URL
  1008. subJsonURL = s.buildSingleURL(configuredSubJsonURI, baseScheme, baseHostWithPort, subJsonPath, subId)
  1009. return subURL, subJsonURL
  1010. }
  1011. // getBaseSchemeAndHost determines the base scheme and host from settings or falls back to request values
  1012. func (s *SubService) getBaseSchemeAndHost(requestScheme, requestHostWithPort string) (string, string) {
  1013. subDomain, err := s.settingService.GetSubDomain()
  1014. if err != nil || subDomain == "" {
  1015. return requestScheme, requestHostWithPort
  1016. }
  1017. // Get port and TLS settings
  1018. subPort, _ := s.settingService.GetSubPort()
  1019. subKeyFile, _ := s.settingService.GetSubKeyFile()
  1020. subCertFile, _ := s.settingService.GetSubCertFile()
  1021. // Determine scheme from TLS configuration
  1022. scheme := "http"
  1023. if subKeyFile != "" && subCertFile != "" {
  1024. scheme = "https"
  1025. }
  1026. // Build host:port, always include port for clarity
  1027. hostWithPort := fmt.Sprintf("%s:%d", subDomain, subPort)
  1028. return scheme, hostWithPort
  1029. }
  1030. // buildSingleURL constructs a single URL using configured URI or base components
  1031. func (s *SubService) buildSingleURL(configuredURI, baseScheme, baseHostWithPort, basePath, subId string) string {
  1032. if configuredURI != "" {
  1033. return s.joinPathWithID(configuredURI, subId)
  1034. }
  1035. baseURL := fmt.Sprintf("%s://%s", baseScheme, baseHostWithPort)
  1036. return s.joinPathWithID(baseURL+basePath, subId)
  1037. }
  1038. // joinPathWithID safely joins a base path with a subscription ID
  1039. func (s *SubService) joinPathWithID(basePath, subId string) string {
  1040. if strings.HasSuffix(basePath, "/") {
  1041. return basePath + subId
  1042. }
  1043. return basePath + "/" + subId
  1044. }
  1045. // BuildPageData parses header and prepares the template view model.
  1046. // BuildPageData constructs page data for rendering the subscription information page.
  1047. func (s *SubService) BuildPageData(subId string, hostHeader string, traffic xray.ClientTraffic, lastOnline int64, subs []string, subURL, subJsonURL string, basePath string) PageData {
  1048. download := common.FormatTraffic(traffic.Down)
  1049. upload := common.FormatTraffic(traffic.Up)
  1050. total := "∞"
  1051. used := common.FormatTraffic(traffic.Up + traffic.Down)
  1052. remained := ""
  1053. if traffic.Total > 0 {
  1054. total = common.FormatTraffic(traffic.Total)
  1055. left := max(traffic.Total-(traffic.Up+traffic.Down), 0)
  1056. remained = common.FormatTraffic(left)
  1057. }
  1058. datepicker := s.datepicker
  1059. if datepicker == "" {
  1060. datepicker = "gregorian"
  1061. }
  1062. return PageData{
  1063. Host: hostHeader,
  1064. BasePath: basePath,
  1065. SId: subId,
  1066. Download: download,
  1067. Upload: upload,
  1068. Total: total,
  1069. Used: used,
  1070. Remained: remained,
  1071. Expire: traffic.ExpiryTime / 1000,
  1072. LastOnline: lastOnline,
  1073. Datepicker: datepicker,
  1074. DownloadByte: traffic.Down,
  1075. UploadByte: traffic.Up,
  1076. TotalByte: traffic.Total,
  1077. SubUrl: subURL,
  1078. SubJsonUrl: subJsonURL,
  1079. Result: subs,
  1080. }
  1081. }
  1082. func getHostFromXFH(s string) (string, error) {
  1083. if strings.Contains(s, ":") {
  1084. realHost, _, err := net.SplitHostPort(s)
  1085. if err != nil {
  1086. return "", err
  1087. }
  1088. return realHost, nil
  1089. }
  1090. return s, nil
  1091. }