subService.go 35 KB

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