| 
									
										
										
										
											2023-05-22 14:36:34 +00:00
										 |  |  |  | package sub | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | import ( | 
					
						
							|  |  |  |  | 	"encoding/base64" | 
					
						
							|  |  |  |  | 	"fmt" | 
					
						
							|  |  |  |  | 	"net/url" | 
					
						
							|  |  |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2023-07-17 23:49:01 +00:00
										 |  |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2024-03-10 21:31:24 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 	"x-ui/database" | 
					
						
							|  |  |  |  | 	"x-ui/database/model" | 
					
						
							|  |  |  |  | 	"x-ui/logger" | 
					
						
							| 
									
										
										
										
											2023-07-17 23:49:01 +00:00
										 |  |  |  | 	"x-ui/util/common" | 
					
						
							| 
									
										
										
										
											2024-03-11 10:04:15 +00:00
										 |  |  |  | 	"x-ui/util/random" | 
					
						
							| 
									
										
										
										
											2023-05-22 14:36:34 +00:00
										 |  |  |  | 	"x-ui/web/service" | 
					
						
							| 
									
										
										
										
											2023-04-18 18:04:06 +00:00
										 |  |  |  | 	"x-ui/xray" | 
					
						
							| 
									
										
										
										
											2023-07-17 23:49:01 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 	"github.com/goccy/go-json" | 
					
						
							|  |  |  |  | ) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | type SubService struct { | 
					
						
							|  |  |  |  | 	address        string | 
					
						
							| 
									
										
										
										
											2023-08-26 11:41:12 +00:00
										 |  |  |  | 	showInfo       bool | 
					
						
							| 
									
										
										
										
											2023-12-08 19:31:17 +00:00
										 |  |  |  | 	remarkModel    string | 
					
						
							| 
									
										
										
										
											2024-01-02 08:32:21 +00:00
										 |  |  |  | 	datepicker     string | 
					
						
							| 
									
										
										
										
											2023-05-22 14:36:34 +00:00
										 |  |  |  | 	inboundService service.InboundService | 
					
						
							| 
									
										
										
										
											2023-12-05 22:09:08 +00:00
										 |  |  |  | 	settingService service.SettingService | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-21 10:47:52 +00:00
										 |  |  |  | func NewSubService(showInfo bool, remarkModel string) *SubService { | 
					
						
							|  |  |  |  | 	return &SubService{ | 
					
						
							|  |  |  |  | 		showInfo:    showInfo, | 
					
						
							|  |  |  |  | 		remarkModel: remarkModel, | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func (s *SubService) GetSubs(subId string, host string) ([]string, string, error) { | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 	s.address = host | 
					
						
							|  |  |  |  | 	var result []string | 
					
						
							| 
									
										
										
										
											2024-02-21 10:47:52 +00:00
										 |  |  |  | 	var header string | 
					
						
							| 
									
										
										
										
											2023-04-18 18:04:06 +00:00
										 |  |  |  | 	var traffic xray.ClientTraffic | 
					
						
							|  |  |  |  | 	var clientTraffics []xray.ClientTraffic | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 	inbounds, err := s.getInboundsBySubId(subId) | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2024-02-21 10:47:52 +00:00
										 |  |  |  | 		return nil, "", err | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-02-21 10:47:52 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-21 06:51:12 +00:00
										 |  |  |  | 	if len(inbounds) == 0 { | 
					
						
							|  |  |  |  | 		return nil, "", common.NewError("No inbounds found with ", subId) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-21 10:47:52 +00:00
										 |  |  |  | 	s.datepicker, err = s.settingService.GetDatepicker() | 
					
						
							| 
									
										
										
										
											2023-12-08 19:31:17 +00:00
										 |  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2024-02-21 10:47:52 +00:00
										 |  |  |  | 		s.datepicker = "gregorian" | 
					
						
							| 
									
										
										
										
											2023-12-08 19:31:17 +00:00
										 |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 	for _, inbound := range inbounds { | 
					
						
							| 
									
										
										
										
											2023-05-22 14:36:34 +00:00
										 |  |  |  | 		clients, err := s.inboundService.GetClients(inbound) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2024-02-21 10:47:52 +00:00
										 |  |  |  | 			logger.Error("SubService - GetClients: Unable to get clients from inbound") | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 		} | 
					
						
							|  |  |  |  | 		if clients == nil { | 
					
						
							|  |  |  |  | 			continue | 
					
						
							|  |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-05-22 23:45:34 +00:00
										 |  |  |  | 		if len(inbound.Listen) > 0 && inbound.Listen[0] == '@' { | 
					
						
							| 
									
										
										
										
											2024-02-21 10:47:52 +00:00
										 |  |  |  | 			listen, port, streamSettings, err := s.getFallbackMaster(inbound.Listen, inbound.StreamSettings) | 
					
						
							| 
									
										
										
										
											2023-05-22 23:45:34 +00:00
										 |  |  |  | 			if err == nil { | 
					
						
							| 
									
										
										
										
											2024-02-21 10:47:52 +00:00
										 |  |  |  | 				inbound.Listen = listen | 
					
						
							|  |  |  |  | 				inbound.Port = port | 
					
						
							|  |  |  |  | 				inbound.StreamSettings = streamSettings | 
					
						
							| 
									
										
										
										
											2023-05-22 23:45:34 +00:00
										 |  |  |  | 			} | 
					
						
							|  |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 		for _, client := range clients { | 
					
						
							| 
									
										
										
										
											2023-05-12 14:59:02 +00:00
										 |  |  |  | 			if client.Enable && client.SubID == subId { | 
					
						
							| 
									
										
										
										
											2023-08-26 11:41:12 +00:00
										 |  |  |  | 				link := s.getLink(inbound, client.Email) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 				result = append(result, link) | 
					
						
							| 
									
										
										
										
											2023-04-18 18:04:06 +00:00
										 |  |  |  | 				clientTraffics = append(clientTraffics, s.getClientTraffics(inbound.ClientStats, client.Email)) | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-02-21 10:47:52 +00:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// Prepare statistics
 | 
					
						
							| 
									
										
										
										
											2023-04-18 18:04:06 +00:00
										 |  |  |  | 	for index, clientTraffic := range clientTraffics { | 
					
						
							|  |  |  |  | 		if index == 0 { | 
					
						
							|  |  |  |  | 			traffic.Up = clientTraffic.Up | 
					
						
							|  |  |  |  | 			traffic.Down = clientTraffic.Down | 
					
						
							|  |  |  |  | 			traffic.Total = clientTraffic.Total | 
					
						
							|  |  |  |  | 			if clientTraffic.ExpiryTime > 0 { | 
					
						
							|  |  |  |  | 				traffic.ExpiryTime = clientTraffic.ExpiryTime | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 		} else { | 
					
						
							|  |  |  |  | 			traffic.Up += clientTraffic.Up | 
					
						
							|  |  |  |  | 			traffic.Down += clientTraffic.Down | 
					
						
							|  |  |  |  | 			if traffic.Total == 0 || clientTraffic.Total == 0 { | 
					
						
							|  |  |  |  | 				traffic.Total = 0 | 
					
						
							|  |  |  |  | 			} else { | 
					
						
							|  |  |  |  | 				traffic.Total += clientTraffic.Total | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 			if clientTraffic.ExpiryTime != traffic.ExpiryTime { | 
					
						
							|  |  |  |  | 				traffic.ExpiryTime = 0 | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 			} | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-02-21 10:47:52 +00:00
										 |  |  |  | 	header = fmt.Sprintf("upload=%d; download=%d; total=%d; expire=%d", traffic.Up, traffic.Down, traffic.Total, traffic.ExpiryTime/1000) | 
					
						
							|  |  |  |  | 	return result, header, nil | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | func (s *SubService) getInboundsBySubId(subId string) ([]*model.Inbound, error) { | 
					
						
							|  |  |  |  | 	db := database.GetDB() | 
					
						
							|  |  |  |  | 	var inbounds []*model.Inbound | 
					
						
							| 
									
										
										
										
											2023-12-08 17:45:21 +00:00
										 |  |  |  | 	err := db.Model(model.Inbound{}).Preload("ClientStats").Where(`id in ( | 
					
						
							|  |  |  |  | 		SELECT DISTINCT inbounds.id | 
					
						
							|  |  |  |  | 		FROM inbounds, | 
					
						
							|  |  |  |  | 			JSON_EACH(JSON_EXTRACT(inbounds.settings, '$.clients')) AS client  | 
					
						
							|  |  |  |  | 		WHERE | 
					
						
							|  |  |  |  | 			protocol in ('vmess','vless','trojan','shadowsocks') | 
					
						
							|  |  |  |  | 			AND JSON_EXTRACT(client.value, '$.subId') = ? AND enable = ? | 
					
						
							|  |  |  |  | 	)`, subId, true).Find(&inbounds).Error | 
					
						
							| 
									
										
										
										
											2023-05-16 21:37:35 +00:00
										 |  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 		return nil, err | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	return inbounds, nil | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-18 18:04:06 +00:00
										 |  |  |  | func (s *SubService) getClientTraffics(traffics []xray.ClientTraffic, email string) xray.ClientTraffic { | 
					
						
							|  |  |  |  | 	for _, traffic := range traffics { | 
					
						
							|  |  |  |  | 		if traffic.Email == email { | 
					
						
							|  |  |  |  | 			return traffic | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	return xray.ClientTraffic{} | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-02-21 10:47:52 +00:00
										 |  |  |  | func (s *SubService) getFallbackMaster(dest string, streamSettings string) (string, int, string, error) { | 
					
						
							| 
									
										
										
										
											2023-05-22 23:45:34 +00:00
										 |  |  |  | 	db := database.GetDB() | 
					
						
							|  |  |  |  | 	var inbound *model.Inbound | 
					
						
							|  |  |  |  | 	err := db.Model(model.Inbound{}). | 
					
						
							|  |  |  |  | 		Where("JSON_TYPE(settings, '$.fallbacks') = 'array'"). | 
					
						
							|  |  |  |  | 		Where("EXISTS (SELECT * FROM json_each(settings, '$.fallbacks') WHERE json_extract(value, '$.dest') = ?)", dest). | 
					
						
							|  |  |  |  | 		Find(&inbound).Error | 
					
						
							|  |  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2024-02-21 10:47:52 +00:00
										 |  |  |  | 		return "", 0, "", err | 
					
						
							| 
									
										
										
										
											2023-05-22 23:45:34 +00:00
										 |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-02-21 10:47:52 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 	var stream map[string]any | 
					
						
							| 
									
										
										
										
											2024-02-21 10:47:52 +00:00
										 |  |  |  | 	json.Unmarshal([]byte(streamSettings), &stream) | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 	var masterStream map[string]any | 
					
						
							| 
									
										
										
										
											2024-02-21 10:47:52 +00:00
										 |  |  |  | 	json.Unmarshal([]byte(inbound.StreamSettings), &masterStream) | 
					
						
							|  |  |  |  | 	stream["security"] = masterStream["security"] | 
					
						
							|  |  |  |  | 	stream["tlsSettings"] = masterStream["tlsSettings"] | 
					
						
							|  |  |  |  | 	stream["externalProxy"] = masterStream["externalProxy"] | 
					
						
							|  |  |  |  | 	modifiedStream, _ := json.MarshalIndent(stream, "", "  ") | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	return inbound.Listen, inbound.Port, string(modifiedStream), nil | 
					
						
							| 
									
										
										
										
											2023-05-22 23:45:34 +00:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-26 11:41:12 +00:00
										 |  |  |  | func (s *SubService) getLink(inbound *model.Inbound, email string) string { | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 	switch inbound.Protocol { | 
					
						
							|  |  |  |  | 	case "vmess": | 
					
						
							| 
									
										
										
										
											2023-08-26 11:41:12 +00:00
										 |  |  |  | 		return s.genVmessLink(inbound, email) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 	case "vless": | 
					
						
							| 
									
										
										
										
											2023-08-26 11:41:12 +00:00
										 |  |  |  | 		return s.genVlessLink(inbound, email) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 	case "trojan": | 
					
						
							| 
									
										
										
										
											2023-08-26 11:41:12 +00:00
										 |  |  |  | 		return s.genTrojanLink(inbound, email) | 
					
						
							| 
									
										
										
										
											2023-05-06 16:51:14 +00:00
										 |  |  |  | 	case "shadowsocks": | 
					
						
							| 
									
										
										
										
											2023-08-26 11:41:12 +00:00
										 |  |  |  | 		return s.genShadowsocksLink(inbound, email) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | 	return "" | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-26 11:41:12 +00:00
										 |  |  |  | func (s *SubService) genVmessLink(inbound *model.Inbound, email string) string { | 
					
						
							| 
									
										
										
										
											2024-08-10 22:47:44 +00:00
										 |  |  |  | 	if inbound.Protocol != model.VMESS { | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 		return "" | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 	obj := map[string]any{ | 
					
						
							| 
									
										
										
										
											2023-04-27 20:45:06 +00:00
										 |  |  |  | 		"v":    "2", | 
					
						
							|  |  |  |  | 		"add":  s.address, | 
					
						
							|  |  |  |  | 		"port": inbound.Port, | 
					
						
							|  |  |  |  | 		"type": "none", | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 	var stream map[string]any | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 	json.Unmarshal([]byte(inbound.StreamSettings), &stream) | 
					
						
							|  |  |  |  | 	network, _ := stream["network"].(string) | 
					
						
							| 
									
										
										
										
											2023-04-27 20:45:06 +00:00
										 |  |  |  | 	obj["net"] = network | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 	switch network { | 
					
						
							|  |  |  |  | 	case "tcp": | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 		tcp, _ := stream["tcpSettings"].(map[string]any) | 
					
						
							|  |  |  |  | 		header, _ := tcp["header"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2023-04-27 20:45:06 +00:00
										 |  |  |  | 		typeStr, _ := header["type"].(string) | 
					
						
							|  |  |  |  | 		obj["type"] = typeStr | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 		if typeStr == "http" { | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 			request := header["request"].(map[string]any) | 
					
						
							|  |  |  |  | 			requestPath, _ := request["path"].([]any) | 
					
						
							| 
									
										
										
										
											2023-04-27 20:45:06 +00:00
										 |  |  |  | 			obj["path"] = requestPath[0].(string) | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 			headers, _ := request["headers"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2023-04-27 20:45:06 +00:00
										 |  |  |  | 			obj["host"] = searchHost(headers) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 		} | 
					
						
							|  |  |  |  | 	case "kcp": | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 		kcp, _ := stream["kcpSettings"].(map[string]any) | 
					
						
							|  |  |  |  | 		header, _ := kcp["header"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2023-04-27 20:45:06 +00:00
										 |  |  |  | 		obj["type"], _ = header["type"].(string) | 
					
						
							|  |  |  |  | 		obj["path"], _ = kcp["seed"].(string) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 	case "ws": | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 		ws, _ := stream["wsSettings"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2023-04-27 20:45:06 +00:00
										 |  |  |  | 		obj["path"] = ws["path"].(string) | 
					
						
							| 
									
										
										
										
											2024-06-18 10:49:20 +00:00
										 |  |  |  | 		if host, ok := ws["host"].(string); ok && len(host) > 0 { | 
					
						
							|  |  |  |  | 			obj["host"] = host | 
					
						
							|  |  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 			headers, _ := ws["headers"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2024-06-18 10:49:20 +00:00
										 |  |  |  | 			obj["host"] = searchHost(headers) | 
					
						
							| 
									
										
										
										
											2024-04-01 12:32:02 +00:00
										 |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 	case "grpc": | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 		grpc, _ := stream["grpcSettings"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2023-04-27 20:45:06 +00:00
										 |  |  |  | 		obj["path"] = grpc["serviceName"].(string) | 
					
						
							| 
									
										
										
										
											2024-03-11 09:30:00 +00:00
										 |  |  |  | 		obj["authority"] = grpc["authority"].(string) | 
					
						
							| 
									
										
										
										
											2023-04-27 20:45:06 +00:00
										 |  |  |  | 		if grpc["multiMode"].(bool) { | 
					
						
							|  |  |  |  | 			obj["type"] = "multi" | 
					
						
							|  |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-03-11 07:36:33 +00:00
										 |  |  |  | 	case "httpupgrade": | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 		httpupgrade, _ := stream["httpupgradeSettings"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2024-03-11 07:36:33 +00:00
										 |  |  |  | 		obj["path"] = httpupgrade["path"].(string) | 
					
						
							| 
									
										
										
										
											2024-06-18 10:49:20 +00:00
										 |  |  |  | 		if host, ok := httpupgrade["host"].(string); ok && len(host) > 0 { | 
					
						
							|  |  |  |  | 			obj["host"] = host | 
					
						
							|  |  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 			headers, _ := httpupgrade["headers"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2024-06-18 10:49:20 +00:00
										 |  |  |  | 			obj["host"] = searchHost(headers) | 
					
						
							|  |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-12-03 21:24:34 +00:00
										 |  |  |  | 	case "xhttp": | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 		xhttp, _ := stream["xhttpSettings"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2024-12-03 21:24:34 +00:00
										 |  |  |  | 		obj["path"] = xhttp["path"].(string) | 
					
						
							|  |  |  |  | 		if host, ok := xhttp["host"].(string); ok && len(host) > 0 { | 
					
						
							| 
									
										
										
										
											2024-06-18 10:49:20 +00:00
										 |  |  |  | 			obj["host"] = host | 
					
						
							|  |  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 			headers, _ := xhttp["headers"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2024-06-18 10:49:20 +00:00
										 |  |  |  | 			obj["host"] = searchHost(headers) | 
					
						
							| 
									
										
										
										
											2024-04-02 20:11:06 +00:00
										 |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-12-03 21:24:34 +00:00
										 |  |  |  | 		obj["mode"] = xhttp["mode"].(string) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | 	security, _ := stream["security"].(string) | 
					
						
							| 
									
										
										
										
											2023-04-27 20:45:06 +00:00
										 |  |  |  | 	obj["tls"] = security | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 	if security == "tls" { | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 		tlsSetting, _ := stream["tlsSettings"].(map[string]any) | 
					
						
							|  |  |  |  | 		alpns, _ := tlsSetting["alpn"].([]any) | 
					
						
							| 
									
										
										
										
											2023-04-27 20:45:06 +00:00
										 |  |  |  | 		if len(alpns) > 0 { | 
					
						
							|  |  |  |  | 			var alpn []string | 
					
						
							|  |  |  |  | 			for _, a := range alpns { | 
					
						
							|  |  |  |  | 				alpn = append(alpn, a.(string)) | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 			obj["alpn"] = strings.Join(alpn, ",") | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-12-08 17:45:21 +00:00
										 |  |  |  | 		if sniValue, ok := searchKey(tlsSetting, "serverName"); ok { | 
					
						
							|  |  |  |  | 			obj["sni"], _ = sniValue.(string) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 		tlsSettings, _ := searchKey(tlsSetting, "settings") | 
					
						
							|  |  |  |  | 		if tlsSetting != nil { | 
					
						
							|  |  |  |  | 			if fpValue, ok := searchKey(tlsSettings, "fingerprint"); ok { | 
					
						
							| 
									
										
										
										
											2023-04-27 20:45:06 +00:00
										 |  |  |  | 				obj["fp"], _ = fpValue.(string) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 			} | 
					
						
							|  |  |  |  | 			if insecure, ok := searchKey(tlsSettings, "allowInsecure"); ok { | 
					
						
							| 
									
										
										
										
											2023-04-27 20:45:06 +00:00
										 |  |  |  | 				obj["allowInsecure"], _ = insecure.(bool) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 			} | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-22 14:36:34 +00:00
										 |  |  |  | 	clients, _ := s.inboundService.GetClients(inbound) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 	clientIndex := -1 | 
					
						
							|  |  |  |  | 	for i, client := range clients { | 
					
						
							|  |  |  |  | 		if client.Email == email { | 
					
						
							|  |  |  |  | 			clientIndex = i | 
					
						
							|  |  |  |  | 			break | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-04-27 20:45:06 +00:00
										 |  |  |  | 	obj["id"] = clients[clientIndex].ID | 
					
						
							| 
									
										
										
										
											2024-08-10 22:47:44 +00:00
										 |  |  |  | 	obj["scy"] = clients[clientIndex].Security | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 	externalProxies, _ := stream["externalProxy"].([]any) | 
					
						
							| 
									
										
										
										
											2023-12-08 17:45:21 +00:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if len(externalProxies) > 0 { | 
					
						
							| 
									
										
										
										
											2023-05-22 14:36:34 +00:00
										 |  |  |  | 		links := "" | 
					
						
							| 
									
										
										
										
											2023-12-08 17:45:21 +00:00
										 |  |  |  | 		for index, externalProxy := range externalProxies { | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 			ep, _ := externalProxy.(map[string]any) | 
					
						
							| 
									
										
										
										
											2023-12-08 17:45:21 +00:00
										 |  |  |  | 			newSecurity, _ := ep["forceTls"].(string) | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 			newObj := map[string]any{} | 
					
						
							| 
									
										
										
										
											2023-12-08 17:45:21 +00:00
										 |  |  |  | 			for key, value := range obj { | 
					
						
							|  |  |  |  | 				if !(newSecurity == "none" && (key == "alpn" || key == "sni" || key == "fp" || key == "allowInsecure")) { | 
					
						
							|  |  |  |  | 					newObj[key] = value | 
					
						
							|  |  |  |  | 				} | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 			newObj["ps"] = s.genRemark(inbound, email, ep["remark"].(string)) | 
					
						
							|  |  |  |  | 			newObj["add"] = ep["dest"].(string) | 
					
						
							|  |  |  |  | 			newObj["port"] = int(ep["port"].(float64)) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			if newSecurity != "same" { | 
					
						
							|  |  |  |  | 				newObj["tls"] = newSecurity | 
					
						
							|  |  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-05-22 14:36:34 +00:00
										 |  |  |  | 			if index > 0 { | 
					
						
							|  |  |  |  | 				links += "\n" | 
					
						
							|  |  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-12-08 17:45:21 +00:00
										 |  |  |  | 			jsonStr, _ := json.MarshalIndent(newObj, "", "  ") | 
					
						
							| 
									
										
										
										
											2023-05-22 14:36:34 +00:00
										 |  |  |  | 			links += "vmess://" + base64.StdEncoding.EncodeToString(jsonStr) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		return links | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-26 11:41:12 +00:00
										 |  |  |  | 	obj["ps"] = s.genRemark(inbound, email, "") | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 	jsonStr, _ := json.MarshalIndent(obj, "", "  ") | 
					
						
							|  |  |  |  | 	return "vmess://" + base64.StdEncoding.EncodeToString(jsonStr) | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-26 11:41:12 +00:00
										 |  |  |  | func (s *SubService) genVlessLink(inbound *model.Inbound, email string) string { | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 	address := s.address | 
					
						
							|  |  |  |  | 	if inbound.Protocol != model.VLESS { | 
					
						
							|  |  |  |  | 		return "" | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 	var stream map[string]any | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 	json.Unmarshal([]byte(inbound.StreamSettings), &stream) | 
					
						
							| 
									
										
										
										
											2023-05-22 14:36:34 +00:00
										 |  |  |  | 	clients, _ := s.inboundService.GetClients(inbound) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 	clientIndex := -1 | 
					
						
							|  |  |  |  | 	for i, client := range clients { | 
					
						
							|  |  |  |  | 		if client.Email == email { | 
					
						
							|  |  |  |  | 			clientIndex = i | 
					
						
							|  |  |  |  | 			break | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	uuid := clients[clientIndex].ID | 
					
						
							|  |  |  |  | 	port := inbound.Port | 
					
						
							|  |  |  |  | 	streamNetwork := stream["network"].(string) | 
					
						
							|  |  |  |  | 	params := make(map[string]string) | 
					
						
							|  |  |  |  | 	params["type"] = streamNetwork | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	switch streamNetwork { | 
					
						
							|  |  |  |  | 	case "tcp": | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 		tcp, _ := stream["tcpSettings"].(map[string]any) | 
					
						
							|  |  |  |  | 		header, _ := tcp["header"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 		typeStr, _ := header["type"].(string) | 
					
						
							|  |  |  |  | 		if typeStr == "http" { | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 			request := header["request"].(map[string]any) | 
					
						
							|  |  |  |  | 			requestPath, _ := request["path"].([]any) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 			params["path"] = requestPath[0].(string) | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 			headers, _ := request["headers"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 			params["host"] = searchHost(headers) | 
					
						
							|  |  |  |  | 			params["headerType"] = "http" | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	case "kcp": | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 		kcp, _ := stream["kcpSettings"].(map[string]any) | 
					
						
							|  |  |  |  | 		header, _ := kcp["header"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 		params["headerType"] = header["type"].(string) | 
					
						
							|  |  |  |  | 		params["seed"] = kcp["seed"].(string) | 
					
						
							|  |  |  |  | 	case "ws": | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 		ws, _ := stream["wsSettings"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 		params["path"] = ws["path"].(string) | 
					
						
							| 
									
										
										
										
											2024-06-18 10:49:20 +00:00
										 |  |  |  | 		if host, ok := ws["host"].(string); ok && len(host) > 0 { | 
					
						
							|  |  |  |  | 			params["host"] = host | 
					
						
							|  |  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 			headers, _ := ws["headers"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2024-06-18 10:49:20 +00:00
										 |  |  |  | 			params["host"] = searchHost(headers) | 
					
						
							| 
									
										
										
										
											2024-04-01 12:32:02 +00:00
										 |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 	case "grpc": | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 		grpc, _ := stream["grpcSettings"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 		params["serviceName"] = grpc["serviceName"].(string) | 
					
						
							| 
									
										
										
										
											2024-04-01 07:39:45 +00:00
										 |  |  |  | 		params["authority"], _ = grpc["authority"].(string) | 
					
						
							| 
									
										
										
										
											2023-04-27 20:45:06 +00:00
										 |  |  |  | 		if grpc["multiMode"].(bool) { | 
					
						
							|  |  |  |  | 			params["mode"] = "multi" | 
					
						
							|  |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-03-11 07:36:33 +00:00
										 |  |  |  | 	case "httpupgrade": | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 		httpupgrade, _ := stream["httpupgradeSettings"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2024-03-11 07:36:33 +00:00
										 |  |  |  | 		params["path"] = httpupgrade["path"].(string) | 
					
						
							| 
									
										
										
										
											2024-06-18 10:49:20 +00:00
										 |  |  |  | 		if host, ok := httpupgrade["host"].(string); ok && len(host) > 0 { | 
					
						
							|  |  |  |  | 			params["host"] = host | 
					
						
							|  |  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 			headers, _ := httpupgrade["headers"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2024-06-18 10:49:20 +00:00
										 |  |  |  | 			params["host"] = searchHost(headers) | 
					
						
							|  |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-12-03 21:24:34 +00:00
										 |  |  |  | 	case "xhttp": | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 		xhttp, _ := stream["xhttpSettings"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2024-12-03 21:24:34 +00:00
										 |  |  |  | 		params["path"] = xhttp["path"].(string) | 
					
						
							|  |  |  |  | 		if host, ok := xhttp["host"].(string); ok && len(host) > 0 { | 
					
						
							| 
									
										
										
										
											2024-06-18 10:49:20 +00:00
										 |  |  |  | 			params["host"] = host | 
					
						
							|  |  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 			headers, _ := xhttp["headers"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2024-06-18 10:49:20 +00:00
										 |  |  |  | 			params["host"] = searchHost(headers) | 
					
						
							| 
									
										
										
										
											2024-04-02 20:11:06 +00:00
										 |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-12-03 21:24:34 +00:00
										 |  |  |  | 		params["mode"] = xhttp["mode"].(string) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | 	security, _ := stream["security"].(string) | 
					
						
							|  |  |  |  | 	if security == "tls" { | 
					
						
							|  |  |  |  | 		params["security"] = "tls" | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 		tlsSetting, _ := stream["tlsSettings"].(map[string]any) | 
					
						
							|  |  |  |  | 		alpns, _ := tlsSetting["alpn"].([]any) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 		var alpn []string | 
					
						
							|  |  |  |  | 		for _, a := range alpns { | 
					
						
							|  |  |  |  | 			alpn = append(alpn, a.(string)) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		if len(alpn) > 0 { | 
					
						
							|  |  |  |  | 			params["alpn"] = strings.Join(alpn, ",") | 
					
						
							|  |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-12-08 17:45:21 +00:00
										 |  |  |  | 		if sniValue, ok := searchKey(tlsSetting, "serverName"); ok { | 
					
						
							|  |  |  |  | 			params["sni"], _ = sniValue.(string) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 		tlsSettings, _ := searchKey(tlsSetting, "settings") | 
					
						
							|  |  |  |  | 		if tlsSetting != nil { | 
					
						
							|  |  |  |  | 			if fpValue, ok := searchKey(tlsSettings, "fingerprint"); ok { | 
					
						
							|  |  |  |  | 				params["fp"], _ = fpValue.(string) | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 			if insecure, ok := searchKey(tlsSettings, "allowInsecure"); ok { | 
					
						
							|  |  |  |  | 				if insecure.(bool) { | 
					
						
							|  |  |  |  | 					params["allowInsecure"] = "1" | 
					
						
							|  |  |  |  | 				} | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		if streamNetwork == "tcp" && len(clients[clientIndex].Flow) > 0 { | 
					
						
							|  |  |  |  | 			params["flow"] = clients[clientIndex].Flow | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-11 12:10:45 +00:00
										 |  |  |  | 	if security == "reality" { | 
					
						
							|  |  |  |  | 		params["security"] = "reality" | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 		realitySetting, _ := stream["realitySettings"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2023-04-19 08:25:31 +00:00
										 |  |  |  | 		realitySettings, _ := searchKey(realitySetting, "settings") | 
					
						
							|  |  |  |  | 		if realitySetting != nil { | 
					
						
							|  |  |  |  | 			if sniValue, ok := searchKey(realitySetting, "serverNames"); ok { | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 				sNames, _ := sniValue.([]any) | 
					
						
							| 
									
										
										
										
											2024-03-11 10:04:15 +00:00
										 |  |  |  | 				params["sni"] = sNames[random.Num(len(sNames))].(string) | 
					
						
							| 
									
										
										
										
											2023-04-11 12:10:45 +00:00
										 |  |  |  | 			} | 
					
						
							|  |  |  |  | 			if pbkValue, ok := searchKey(realitySettings, "publicKey"); ok { | 
					
						
							|  |  |  |  | 				params["pbk"], _ = pbkValue.(string) | 
					
						
							|  |  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-04-19 08:25:31 +00:00
										 |  |  |  | 			if sidValue, ok := searchKey(realitySetting, "shortIds"); ok { | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 				shortIds, _ := sidValue.([]any) | 
					
						
							| 
									
										
										
										
											2024-03-11 10:04:15 +00:00
										 |  |  |  | 				params["sid"] = shortIds[random.Num(len(shortIds))].(string) | 
					
						
							| 
									
										
										
										
											2023-04-11 12:10:45 +00:00
										 |  |  |  | 			} | 
					
						
							|  |  |  |  | 			if fpValue, ok := searchKey(realitySettings, "fingerprint"); ok { | 
					
						
							| 
									
										
										
										
											2023-04-19 08:25:31 +00:00
										 |  |  |  | 				if fp, ok := fpValue.(string); ok && len(fp) > 0 { | 
					
						
							|  |  |  |  | 					params["fp"] = fp | 
					
						
							|  |  |  |  | 				} | 
					
						
							|  |  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2024-03-11 10:04:15 +00:00
										 |  |  |  | 			params["spx"] = "/" + random.Seq(15) | 
					
						
							| 
									
										
										
										
											2023-04-11 12:10:45 +00:00
										 |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		if streamNetwork == "tcp" && len(clients[clientIndex].Flow) > 0 { | 
					
						
							|  |  |  |  | 			params["flow"] = clients[clientIndex].Flow | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-29 11:50:25 +00:00
										 |  |  |  | 	if security != "tls" && security != "reality" { | 
					
						
							| 
									
										
										
										
											2023-06-14 13:36:56 +00:00
										 |  |  |  | 		params["security"] = "none" | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 	externalProxies, _ := stream["externalProxy"].([]any) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-08 17:45:21 +00:00
										 |  |  |  | 	if len(externalProxies) > 0 { | 
					
						
							|  |  |  |  | 		links := "" | 
					
						
							|  |  |  |  | 		for index, externalProxy := range externalProxies { | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 			ep, _ := externalProxy.(map[string]any) | 
					
						
							| 
									
										
										
										
											2023-12-08 17:45:21 +00:00
										 |  |  |  | 			newSecurity, _ := ep["forceTls"].(string) | 
					
						
							|  |  |  |  | 			dest, _ := ep["dest"].(string) | 
					
						
							|  |  |  |  | 			port := int(ep["port"].(float64)) | 
					
						
							|  |  |  |  | 			link := fmt.Sprintf("vless://%s@%s:%d", uuid, dest, port) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			if newSecurity != "same" { | 
					
						
							|  |  |  |  | 				params["security"] = newSecurity | 
					
						
							|  |  |  |  | 			} else { | 
					
						
							|  |  |  |  | 				params["security"] = security | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 			url, _ := url.Parse(link) | 
					
						
							|  |  |  |  | 			q := url.Query() | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-08 17:45:21 +00:00
										 |  |  |  | 			for k, v := range params { | 
					
						
							|  |  |  |  | 				if !(newSecurity == "none" && (k == "alpn" || k == "sni" || k == "fp" || k == "allowInsecure")) { | 
					
						
							|  |  |  |  | 					q.Add(k, v) | 
					
						
							|  |  |  |  | 				} | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			// Set the new query values on the URL
 | 
					
						
							|  |  |  |  | 			url.RawQuery = q.Encode() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			url.Fragment = s.genRemark(inbound, email, ep["remark"].(string)) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-22 14:36:34 +00:00
										 |  |  |  | 			if index > 0 { | 
					
						
							|  |  |  |  | 				links += "\n" | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 			links += url.String() | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		return links | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-08-26 11:41:12 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-08 17:45:21 +00:00
										 |  |  |  | 	link := fmt.Sprintf("vless://%s@%s:%d", uuid, address, port) | 
					
						
							|  |  |  |  | 	url, _ := url.Parse(link) | 
					
						
							|  |  |  |  | 	q := url.Query() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	for k, v := range params { | 
					
						
							|  |  |  |  | 		q.Add(k, v) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// Set the new query values on the URL
 | 
					
						
							|  |  |  |  | 	url.RawQuery = q.Encode() | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-26 11:41:12 +00:00
										 |  |  |  | 	url.Fragment = s.genRemark(inbound, email, "") | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 	return url.String() | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-26 11:41:12 +00:00
										 |  |  |  | func (s *SubService) genTrojanLink(inbound *model.Inbound, email string) string { | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 	address := s.address | 
					
						
							|  |  |  |  | 	if inbound.Protocol != model.Trojan { | 
					
						
							|  |  |  |  | 		return "" | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 	var stream map[string]any | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 	json.Unmarshal([]byte(inbound.StreamSettings), &stream) | 
					
						
							| 
									
										
										
										
											2023-05-22 14:36:34 +00:00
										 |  |  |  | 	clients, _ := s.inboundService.GetClients(inbound) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 	clientIndex := -1 | 
					
						
							|  |  |  |  | 	for i, client := range clients { | 
					
						
							|  |  |  |  | 		if client.Email == email { | 
					
						
							|  |  |  |  | 			clientIndex = i | 
					
						
							|  |  |  |  | 			break | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	password := clients[clientIndex].Password | 
					
						
							|  |  |  |  | 	port := inbound.Port | 
					
						
							|  |  |  |  | 	streamNetwork := stream["network"].(string) | 
					
						
							|  |  |  |  | 	params := make(map[string]string) | 
					
						
							|  |  |  |  | 	params["type"] = streamNetwork | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	switch streamNetwork { | 
					
						
							|  |  |  |  | 	case "tcp": | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 		tcp, _ := stream["tcpSettings"].(map[string]any) | 
					
						
							|  |  |  |  | 		header, _ := tcp["header"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 		typeStr, _ := header["type"].(string) | 
					
						
							|  |  |  |  | 		if typeStr == "http" { | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 			request := header["request"].(map[string]any) | 
					
						
							|  |  |  |  | 			requestPath, _ := request["path"].([]any) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 			params["path"] = requestPath[0].(string) | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 			headers, _ := request["headers"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 			params["host"] = searchHost(headers) | 
					
						
							|  |  |  |  | 			params["headerType"] = "http" | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	case "kcp": | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 		kcp, _ := stream["kcpSettings"].(map[string]any) | 
					
						
							|  |  |  |  | 		header, _ := kcp["header"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 		params["headerType"] = header["type"].(string) | 
					
						
							|  |  |  |  | 		params["seed"] = kcp["seed"].(string) | 
					
						
							|  |  |  |  | 	case "ws": | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 		ws, _ := stream["wsSettings"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 		params["path"] = ws["path"].(string) | 
					
						
							| 
									
										
										
										
											2024-06-18 10:49:20 +00:00
										 |  |  |  | 		if host, ok := ws["host"].(string); ok && len(host) > 0 { | 
					
						
							|  |  |  |  | 			params["host"] = host | 
					
						
							|  |  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 			headers, _ := ws["headers"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2024-06-18 10:49:20 +00:00
										 |  |  |  | 			params["host"] = searchHost(headers) | 
					
						
							| 
									
										
										
										
											2024-04-01 12:32:02 +00:00
										 |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 	case "grpc": | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 		grpc, _ := stream["grpcSettings"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 		params["serviceName"] = grpc["serviceName"].(string) | 
					
						
							| 
									
										
										
										
											2024-04-01 07:39:45 +00:00
										 |  |  |  | 		params["authority"], _ = grpc["authority"].(string) | 
					
						
							| 
									
										
										
										
											2023-04-27 20:45:06 +00:00
										 |  |  |  | 		if grpc["multiMode"].(bool) { | 
					
						
							|  |  |  |  | 			params["mode"] = "multi" | 
					
						
							|  |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-03-11 07:36:33 +00:00
										 |  |  |  | 	case "httpupgrade": | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 		httpupgrade, _ := stream["httpupgradeSettings"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2024-03-11 07:36:33 +00:00
										 |  |  |  | 		params["path"] = httpupgrade["path"].(string) | 
					
						
							| 
									
										
										
										
											2024-06-18 10:49:20 +00:00
										 |  |  |  | 		if host, ok := httpupgrade["host"].(string); ok && len(host) > 0 { | 
					
						
							|  |  |  |  | 			params["host"] = host | 
					
						
							|  |  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 			headers, _ := httpupgrade["headers"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2024-06-18 10:49:20 +00:00
										 |  |  |  | 			params["host"] = searchHost(headers) | 
					
						
							|  |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-12-03 21:24:34 +00:00
										 |  |  |  | 	case "xhttp": | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 		xhttp, _ := stream["xhttpSettings"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2024-12-03 21:24:34 +00:00
										 |  |  |  | 		params["path"] = xhttp["path"].(string) | 
					
						
							|  |  |  |  | 		if host, ok := xhttp["host"].(string); ok && len(host) > 0 { | 
					
						
							| 
									
										
										
										
											2024-06-18 10:49:20 +00:00
										 |  |  |  | 			params["host"] = host | 
					
						
							|  |  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 			headers, _ := xhttp["headers"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2024-06-18 10:49:20 +00:00
										 |  |  |  | 			params["host"] = searchHost(headers) | 
					
						
							| 
									
										
										
										
											2024-04-02 20:11:06 +00:00
										 |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-12-03 21:24:34 +00:00
										 |  |  |  | 		params["mode"] = xhttp["mode"].(string) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | 	security, _ := stream["security"].(string) | 
					
						
							|  |  |  |  | 	if security == "tls" { | 
					
						
							|  |  |  |  | 		params["security"] = "tls" | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 		tlsSetting, _ := stream["tlsSettings"].(map[string]any) | 
					
						
							|  |  |  |  | 		alpns, _ := tlsSetting["alpn"].([]any) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 		var alpn []string | 
					
						
							|  |  |  |  | 		for _, a := range alpns { | 
					
						
							|  |  |  |  | 			alpn = append(alpn, a.(string)) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		if len(alpn) > 0 { | 
					
						
							|  |  |  |  | 			params["alpn"] = strings.Join(alpn, ",") | 
					
						
							|  |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-12-08 17:45:21 +00:00
										 |  |  |  | 		if sniValue, ok := searchKey(tlsSetting, "serverName"); ok { | 
					
						
							|  |  |  |  | 			params["sni"], _ = sniValue.(string) | 
					
						
							|  |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-02-21 10:47:52 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 		tlsSettings, _ := searchKey(tlsSetting, "settings") | 
					
						
							|  |  |  |  | 		if tlsSetting != nil { | 
					
						
							|  |  |  |  | 			if fpValue, ok := searchKey(tlsSettings, "fingerprint"); ok { | 
					
						
							|  |  |  |  | 				params["fp"], _ = fpValue.(string) | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 			if insecure, ok := searchKey(tlsSettings, "allowInsecure"); ok { | 
					
						
							|  |  |  |  | 				if insecure.(bool) { | 
					
						
							|  |  |  |  | 					params["allowInsecure"] = "1" | 
					
						
							|  |  |  |  | 				} | 
					
						
							|  |  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-04-11 19:00:24 +00:00
										 |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if security == "reality" { | 
					
						
							|  |  |  |  | 		params["security"] = "reality" | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 		realitySetting, _ := stream["realitySettings"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2023-04-19 08:25:31 +00:00
										 |  |  |  | 		realitySettings, _ := searchKey(realitySetting, "settings") | 
					
						
							|  |  |  |  | 		if realitySetting != nil { | 
					
						
							|  |  |  |  | 			if sniValue, ok := searchKey(realitySetting, "serverNames"); ok { | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 				sNames, _ := sniValue.([]any) | 
					
						
							| 
									
										
										
										
											2024-03-11 10:04:15 +00:00
										 |  |  |  | 				params["sni"] = sNames[random.Num(len(sNames))].(string) | 
					
						
							| 
									
										
										
										
											2023-04-11 19:00:24 +00:00
										 |  |  |  | 			} | 
					
						
							|  |  |  |  | 			if pbkValue, ok := searchKey(realitySettings, "publicKey"); ok { | 
					
						
							|  |  |  |  | 				params["pbk"], _ = pbkValue.(string) | 
					
						
							|  |  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-06-07 09:15:58 +00:00
										 |  |  |  | 			if sidValue, ok := searchKey(realitySetting, "shortIds"); ok { | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 				shortIds, _ := sidValue.([]any) | 
					
						
							| 
									
										
										
										
											2024-03-11 10:04:15 +00:00
										 |  |  |  | 				params["sid"] = shortIds[random.Num(len(shortIds))].(string) | 
					
						
							| 
									
										
										
										
											2023-04-11 19:00:24 +00:00
										 |  |  |  | 			} | 
					
						
							|  |  |  |  | 			if fpValue, ok := searchKey(realitySettings, "fingerprint"); ok { | 
					
						
							| 
									
										
										
										
											2023-04-19 08:25:31 +00:00
										 |  |  |  | 				if fp, ok := fpValue.(string); ok && len(fp) > 0 { | 
					
						
							|  |  |  |  | 					params["fp"] = fp | 
					
						
							|  |  |  |  | 				} | 
					
						
							|  |  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2024-03-11 10:04:15 +00:00
										 |  |  |  | 			params["spx"] = "/" + random.Seq(15) | 
					
						
							| 
									
										
										
										
											2023-04-11 19:00:24 +00:00
										 |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-04-12 08:44:07 +00:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 		if streamNetwork == "tcp" && len(clients[clientIndex].Flow) > 0 { | 
					
						
							|  |  |  |  | 			params["flow"] = clients[clientIndex].Flow | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-10-29 11:50:25 +00:00
										 |  |  |  | 	if security != "tls" && security != "reality" { | 
					
						
							| 
									
										
										
										
											2023-06-14 13:36:56 +00:00
										 |  |  |  | 		params["security"] = "none" | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 	externalProxies, _ := stream["externalProxy"].([]any) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-08 17:45:21 +00:00
										 |  |  |  | 	if len(externalProxies) > 0 { | 
					
						
							|  |  |  |  | 		links := "" | 
					
						
							|  |  |  |  | 		for index, externalProxy := range externalProxies { | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 			ep, _ := externalProxy.(map[string]any) | 
					
						
							| 
									
										
										
										
											2023-12-08 17:45:21 +00:00
										 |  |  |  | 			newSecurity, _ := ep["forceTls"].(string) | 
					
						
							|  |  |  |  | 			dest, _ := ep["dest"].(string) | 
					
						
							|  |  |  |  | 			port := int(ep["port"].(float64)) | 
					
						
							|  |  |  |  | 			link := fmt.Sprintf("trojan://%s@%s:%d", password, dest, port) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			if newSecurity != "same" { | 
					
						
							|  |  |  |  | 				params["security"] = newSecurity | 
					
						
							|  |  |  |  | 			} else { | 
					
						
							|  |  |  |  | 				params["security"] = security | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 			url, _ := url.Parse(link) | 
					
						
							|  |  |  |  | 			q := url.Query() | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-08 17:45:21 +00:00
										 |  |  |  | 			for k, v := range params { | 
					
						
							|  |  |  |  | 				if !(newSecurity == "none" && (k == "alpn" || k == "sni" || k == "fp" || k == "allowInsecure")) { | 
					
						
							|  |  |  |  | 					q.Add(k, v) | 
					
						
							|  |  |  |  | 				} | 
					
						
							|  |  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-08 17:45:21 +00:00
										 |  |  |  | 			// Set the new query values on the URL
 | 
					
						
							|  |  |  |  | 			url.RawQuery = q.Encode() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			url.Fragment = s.genRemark(inbound, email, ep["remark"].(string)) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-22 14:36:34 +00:00
										 |  |  |  | 			if index > 0 { | 
					
						
							|  |  |  |  | 				links += "\n" | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 			links += url.String() | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		return links | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-08 17:45:21 +00:00
										 |  |  |  | 	link := fmt.Sprintf("trojan://%s@%s:%d", password, address, port) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	url, _ := url.Parse(link) | 
					
						
							|  |  |  |  | 	q := url.Query() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	for k, v := range params { | 
					
						
							|  |  |  |  | 		q.Add(k, v) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// Set the new query values on the URL
 | 
					
						
							|  |  |  |  | 	url.RawQuery = q.Encode() | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-26 11:41:12 +00:00
										 |  |  |  | 	url.Fragment = s.genRemark(inbound, email, "") | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 	return url.String() | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-26 11:41:12 +00:00
										 |  |  |  | func (s *SubService) genShadowsocksLink(inbound *model.Inbound, email string) string { | 
					
						
							| 
									
										
										
										
											2023-05-06 16:51:14 +00:00
										 |  |  |  | 	address := s.address | 
					
						
							|  |  |  |  | 	if inbound.Protocol != model.Shadowsocks { | 
					
						
							|  |  |  |  | 		return "" | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 	var stream map[string]any | 
					
						
							| 
									
										
										
										
											2023-07-17 23:49:01 +00:00
										 |  |  |  | 	json.Unmarshal([]byte(inbound.StreamSettings), &stream) | 
					
						
							| 
									
										
										
										
											2023-05-22 14:36:34 +00:00
										 |  |  |  | 	clients, _ := s.inboundService.GetClients(inbound) | 
					
						
							| 
									
										
										
										
											2023-05-06 16:51:14 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 	var settings map[string]any | 
					
						
							| 
									
										
										
										
											2023-05-06 16:51:14 +00:00
										 |  |  |  | 	json.Unmarshal([]byte(inbound.Settings), &settings) | 
					
						
							|  |  |  |  | 	inboundPassword := settings["password"].(string) | 
					
						
							|  |  |  |  | 	method := settings["method"].(string) | 
					
						
							|  |  |  |  | 	clientIndex := -1 | 
					
						
							|  |  |  |  | 	for i, client := range clients { | 
					
						
							|  |  |  |  | 		if client.Email == email { | 
					
						
							|  |  |  |  | 			clientIndex = i | 
					
						
							|  |  |  |  | 			break | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-07-17 23:49:01 +00:00
										 |  |  |  | 	streamNetwork := stream["network"].(string) | 
					
						
							|  |  |  |  | 	params := make(map[string]string) | 
					
						
							|  |  |  |  | 	params["type"] = streamNetwork | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	switch streamNetwork { | 
					
						
							|  |  |  |  | 	case "tcp": | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 		tcp, _ := stream["tcpSettings"].(map[string]any) | 
					
						
							|  |  |  |  | 		header, _ := tcp["header"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2023-07-17 23:49:01 +00:00
										 |  |  |  | 		typeStr, _ := header["type"].(string) | 
					
						
							|  |  |  |  | 		if typeStr == "http" { | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 			request := header["request"].(map[string]any) | 
					
						
							|  |  |  |  | 			requestPath, _ := request["path"].([]any) | 
					
						
							| 
									
										
										
										
											2023-07-17 23:49:01 +00:00
										 |  |  |  | 			params["path"] = requestPath[0].(string) | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 			headers, _ := request["headers"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2023-07-17 23:49:01 +00:00
										 |  |  |  | 			params["host"] = searchHost(headers) | 
					
						
							|  |  |  |  | 			params["headerType"] = "http" | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	case "kcp": | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 		kcp, _ := stream["kcpSettings"].(map[string]any) | 
					
						
							|  |  |  |  | 		header, _ := kcp["header"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2023-07-17 23:49:01 +00:00
										 |  |  |  | 		params["headerType"] = header["type"].(string) | 
					
						
							|  |  |  |  | 		params["seed"] = kcp["seed"].(string) | 
					
						
							|  |  |  |  | 	case "ws": | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 		ws, _ := stream["wsSettings"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2023-07-17 23:49:01 +00:00
										 |  |  |  | 		params["path"] = ws["path"].(string) | 
					
						
							| 
									
										
										
										
											2024-06-18 10:49:20 +00:00
										 |  |  |  | 		if host, ok := ws["host"].(string); ok && len(host) > 0 { | 
					
						
							|  |  |  |  | 			params["host"] = host | 
					
						
							|  |  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 			headers, _ := ws["headers"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2024-06-18 10:49:20 +00:00
										 |  |  |  | 			params["host"] = searchHost(headers) | 
					
						
							| 
									
										
										
										
											2024-04-01 12:32:02 +00:00
										 |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-07-17 23:49:01 +00:00
										 |  |  |  | 	case "grpc": | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 		grpc, _ := stream["grpcSettings"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2023-07-17 23:49:01 +00:00
										 |  |  |  | 		params["serviceName"] = grpc["serviceName"].(string) | 
					
						
							| 
									
										
										
										
											2024-04-01 07:39:45 +00:00
										 |  |  |  | 		params["authority"], _ = grpc["authority"].(string) | 
					
						
							| 
									
										
										
										
											2023-07-17 23:49:01 +00:00
										 |  |  |  | 		if grpc["multiMode"].(bool) { | 
					
						
							|  |  |  |  | 			params["mode"] = "multi" | 
					
						
							|  |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-03-11 07:36:33 +00:00
										 |  |  |  | 	case "httpupgrade": | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 		httpupgrade, _ := stream["httpupgradeSettings"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2024-03-11 07:36:33 +00:00
										 |  |  |  | 		params["path"] = httpupgrade["path"].(string) | 
					
						
							| 
									
										
										
										
											2024-06-18 10:49:20 +00:00
										 |  |  |  | 		if host, ok := httpupgrade["host"].(string); ok && len(host) > 0 { | 
					
						
							|  |  |  |  | 			params["host"] = host | 
					
						
							|  |  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 			headers, _ := httpupgrade["headers"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2024-06-18 10:49:20 +00:00
										 |  |  |  | 			params["host"] = searchHost(headers) | 
					
						
							|  |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-12-03 21:24:34 +00:00
										 |  |  |  | 	case "xhttp": | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 		xhttp, _ := stream["xhttpSettings"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2024-12-03 21:24:34 +00:00
										 |  |  |  | 		params["path"] = xhttp["path"].(string) | 
					
						
							|  |  |  |  | 		if host, ok := xhttp["host"].(string); ok && len(host) > 0 { | 
					
						
							| 
									
										
										
										
											2024-06-18 10:49:20 +00:00
										 |  |  |  | 			params["host"] = host | 
					
						
							|  |  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 			headers, _ := xhttp["headers"].(map[string]any) | 
					
						
							| 
									
										
										
										
											2024-06-18 10:49:20 +00:00
										 |  |  |  | 			params["host"] = searchHost(headers) | 
					
						
							| 
									
										
										
										
											2024-04-02 20:11:06 +00:00
										 |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-12-03 21:24:34 +00:00
										 |  |  |  | 		params["mode"] = xhttp["mode"].(string) | 
					
						
							| 
									
										
										
										
											2023-07-17 23:49:01 +00:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-12-08 17:45:21 +00:00
										 |  |  |  | 	security, _ := stream["security"].(string) | 
					
						
							|  |  |  |  | 	if security == "tls" { | 
					
						
							|  |  |  |  | 		params["security"] = "tls" | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 		tlsSetting, _ := stream["tlsSettings"].(map[string]any) | 
					
						
							|  |  |  |  | 		alpns, _ := tlsSetting["alpn"].([]any) | 
					
						
							| 
									
										
										
										
											2023-12-08 17:45:21 +00:00
										 |  |  |  | 		var alpn []string | 
					
						
							|  |  |  |  | 		for _, a := range alpns { | 
					
						
							|  |  |  |  | 			alpn = append(alpn, a.(string)) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		if len(alpn) > 0 { | 
					
						
							|  |  |  |  | 			params["alpn"] = strings.Join(alpn, ",") | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		if sniValue, ok := searchKey(tlsSetting, "serverName"); ok { | 
					
						
							|  |  |  |  | 			params["sni"], _ = sniValue.(string) | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		tlsSettings, _ := searchKey(tlsSetting, "settings") | 
					
						
							|  |  |  |  | 		if tlsSetting != nil { | 
					
						
							|  |  |  |  | 			if fpValue, ok := searchKey(tlsSettings, "fingerprint"); ok { | 
					
						
							|  |  |  |  | 				params["fp"], _ = fpValue.(string) | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 			if insecure, ok := searchKey(tlsSettings, "allowInsecure"); ok { | 
					
						
							|  |  |  |  | 				if insecure.(bool) { | 
					
						
							|  |  |  |  | 					params["allowInsecure"] = "1" | 
					
						
							|  |  |  |  | 				} | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-27 08:28:12 +00:00
										 |  |  |  | 	encPart := fmt.Sprintf("%s:%s", method, clients[clientIndex].Password) | 
					
						
							|  |  |  |  | 	if method[0] == '2' { | 
					
						
							|  |  |  |  | 		encPart = fmt.Sprintf("%s:%s:%s", method, inboundPassword, clients[clientIndex].Password) | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-12-08 17:45:21 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 	externalProxies, _ := stream["externalProxy"].([]any) | 
					
						
							| 
									
										
										
										
											2023-12-08 17:45:21 +00:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if len(externalProxies) > 0 { | 
					
						
							|  |  |  |  | 		links := "" | 
					
						
							|  |  |  |  | 		for index, externalProxy := range externalProxies { | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 			ep, _ := externalProxy.(map[string]any) | 
					
						
							| 
									
										
										
										
											2023-12-08 17:45:21 +00:00
										 |  |  |  | 			newSecurity, _ := ep["forceTls"].(string) | 
					
						
							|  |  |  |  | 			dest, _ := ep["dest"].(string) | 
					
						
							|  |  |  |  | 			port := int(ep["port"].(float64)) | 
					
						
							|  |  |  |  | 			link := fmt.Sprintf("ss://%s@%s:%d", base64.StdEncoding.EncodeToString([]byte(encPart)), dest, port) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			if newSecurity != "same" { | 
					
						
							|  |  |  |  | 				params["security"] = newSecurity | 
					
						
							|  |  |  |  | 			} else { | 
					
						
							|  |  |  |  | 				params["security"] = security | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 			url, _ := url.Parse(link) | 
					
						
							|  |  |  |  | 			q := url.Query() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			for k, v := range params { | 
					
						
							|  |  |  |  | 				if !(newSecurity == "none" && (k == "alpn" || k == "sni" || k == "fp" || k == "allowInsecure")) { | 
					
						
							|  |  |  |  | 					q.Add(k, v) | 
					
						
							|  |  |  |  | 				} | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			// Set the new query values on the URL
 | 
					
						
							|  |  |  |  | 			url.RawQuery = q.Encode() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			url.Fragment = s.genRemark(inbound, email, ep["remark"].(string)) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 			if index > 0 { | 
					
						
							|  |  |  |  | 				links += "\n" | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 			links += url.String() | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 		return links | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-17 23:49:01 +00:00
										 |  |  |  | 	link := fmt.Sprintf("ss://%s@%s:%d", base64.StdEncoding.EncodeToString([]byte(encPart)), address, inbound.Port) | 
					
						
							|  |  |  |  | 	url, _ := url.Parse(link) | 
					
						
							|  |  |  |  | 	q := url.Query() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	for k, v := range params { | 
					
						
							|  |  |  |  | 		q.Add(k, v) | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	// Set the new query values on the URL
 | 
					
						
							|  |  |  |  | 	url.RawQuery = q.Encode() | 
					
						
							| 
									
										
										
										
											2023-12-08 17:45:21 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-26 11:41:12 +00:00
										 |  |  |  | 	url.Fragment = s.genRemark(inbound, email, "") | 
					
						
							|  |  |  |  | 	return url.String() | 
					
						
							|  |  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-07-17 23:49:01 +00:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-26 11:41:12 +00:00
										 |  |  |  | func (s *SubService) genRemark(inbound *model.Inbound, email string, extra string) string { | 
					
						
							| 
									
										
										
										
											2023-12-08 19:31:17 +00:00
										 |  |  |  | 	separationChar := string(s.remarkModel[0]) | 
					
						
							|  |  |  |  | 	orderChars := s.remarkModel[1:] | 
					
						
							|  |  |  |  | 	orders := map[byte]string{ | 
					
						
							|  |  |  |  | 		'i': "", | 
					
						
							|  |  |  |  | 		'e': "", | 
					
						
							|  |  |  |  | 		'o': "", | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-08-26 11:41:12 +00:00
										 |  |  |  | 	if len(email) > 0 { | 
					
						
							| 
									
										
										
										
											2023-12-08 19:31:17 +00:00
										 |  |  |  | 		orders['e'] = email | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if len(inbound.Remark) > 0 { | 
					
						
							|  |  |  |  | 		orders['i'] = inbound.Remark | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	if len(extra) > 0 { | 
					
						
							| 
									
										
										
										
											2023-12-10 17:13:48 +00:00
										 |  |  |  | 		orders['o'] = extra | 
					
						
							| 
									
										
										
										
											2023-12-08 19:31:17 +00:00
										 |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	var remark []string | 
					
						
							|  |  |  |  | 	for i := 0; i < len(orderChars); i++ { | 
					
						
							|  |  |  |  | 		char := orderChars[i] | 
					
						
							|  |  |  |  | 		order, exists := orders[char] | 
					
						
							|  |  |  |  | 		if exists && order != "" { | 
					
						
							|  |  |  |  | 			remark = append(remark, order) | 
					
						
							| 
									
										
										
										
											2023-08-26 11:41:12 +00:00
										 |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-08-01 20:58:51 +00:00
										 |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-08-26 11:41:12 +00:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 	if s.showInfo { | 
					
						
							|  |  |  |  | 		statsExist := false | 
					
						
							|  |  |  |  | 		var stats xray.ClientTraffic | 
					
						
							|  |  |  |  | 		for _, clientStat := range inbound.ClientStats { | 
					
						
							|  |  |  |  | 			if clientStat.Email == email { | 
					
						
							|  |  |  |  | 				stats = clientStat | 
					
						
							|  |  |  |  | 				statsExist = true | 
					
						
							|  |  |  |  | 				break | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 		// Get remained days
 | 
					
						
							|  |  |  |  | 		if statsExist { | 
					
						
							|  |  |  |  | 			if !stats.Enable { | 
					
						
							| 
									
										
										
										
											2023-12-08 19:31:17 +00:00
										 |  |  |  | 				return fmt.Sprintf("⛔️N/A%s%s", separationChar, strings.Join(remark, separationChar)) | 
					
						
							| 
									
										
										
										
											2023-08-26 11:41:12 +00:00
										 |  |  |  | 			} | 
					
						
							|  |  |  |  | 			if vol := stats.Total - (stats.Up + stats.Down); vol > 0 { | 
					
						
							|  |  |  |  | 				remark = append(remark, fmt.Sprintf("%s%s", common.FormatTraffic(vol), "📊")) | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 			now := time.Now().Unix() | 
					
						
							|  |  |  |  | 			switch exp := stats.ExpiryTime / 1000; { | 
					
						
							|  |  |  |  | 			case exp > 0: | 
					
						
							| 
									
										
										
										
											2024-07-01 17:11:40 +00:00
										 |  |  |  | 				remainingSeconds := exp - now | 
					
						
							|  |  |  |  | 				days := remainingSeconds / 86400 | 
					
						
							|  |  |  |  | 				hours := (remainingSeconds % 86400) / 3600 | 
					
						
							|  |  |  |  | 				minutes := (remainingSeconds % 3600) / 60 | 
					
						
							|  |  |  |  | 				if days > 0 { | 
					
						
							|  |  |  |  | 					if hours > 0 { | 
					
						
							|  |  |  |  | 						remark = append(remark, fmt.Sprintf("%dD,%dH⏳", days, hours)) | 
					
						
							|  |  |  |  | 					} else { | 
					
						
							|  |  |  |  | 						remark = append(remark, fmt.Sprintf("%dD⏳", days)) | 
					
						
							|  |  |  |  | 					} | 
					
						
							|  |  |  |  | 				} else if hours > 0 { | 
					
						
							|  |  |  |  | 					remark = append(remark, fmt.Sprintf("%dH⏳", hours)) | 
					
						
							|  |  |  |  | 				} else { | 
					
						
							|  |  |  |  | 					remark = append(remark, fmt.Sprintf("%dM⏳", minutes)) | 
					
						
							|  |  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2023-08-26 11:41:12 +00:00
										 |  |  |  | 			case exp < 0: | 
					
						
							| 
									
										
										
										
											2024-07-17 14:39:53 +00:00
										 |  |  |  | 				days := exp / -86400 | 
					
						
							|  |  |  |  | 				hours := (exp % -86400) / 3600 | 
					
						
							|  |  |  |  | 				minutes := (exp % -3600) / 60 | 
					
						
							| 
									
										
										
										
											2024-07-01 17:11:40 +00:00
										 |  |  |  | 				if days > 0 { | 
					
						
							|  |  |  |  | 					if hours > 0 { | 
					
						
							|  |  |  |  | 						remark = append(remark, fmt.Sprintf("%dD,%dH⏳", days, hours)) | 
					
						
							|  |  |  |  | 					} else { | 
					
						
							|  |  |  |  | 						remark = append(remark, fmt.Sprintf("%dD⏳", days)) | 
					
						
							|  |  |  |  | 					} | 
					
						
							|  |  |  |  | 				} else if hours > 0 { | 
					
						
							|  |  |  |  | 					remark = append(remark, fmt.Sprintf("%dH⏳", hours)) | 
					
						
							|  |  |  |  | 				} else { | 
					
						
							|  |  |  |  | 					remark = append(remark, fmt.Sprintf("%dM⏳", minutes)) | 
					
						
							|  |  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2023-08-26 11:41:12 +00:00
										 |  |  |  | 			} | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-12-08 19:31:17 +00:00
										 |  |  |  | 	return strings.Join(remark, separationChar) | 
					
						
							| 
									
										
										
										
											2023-05-06 16:51:14 +00:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | func searchKey(data any, key string) (any, bool) { | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 	switch val := data.(type) { | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 	case map[string]any: | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 		for k, v := range val { | 
					
						
							|  |  |  |  | 			if k == key { | 
					
						
							|  |  |  |  | 				return v, true | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 			if result, ok := searchKey(v, key); ok { | 
					
						
							|  |  |  |  | 				return result, true | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 	case []any: | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 		for _, v := range val { | 
					
						
							|  |  |  |  | 			if result, ok := searchKey(v, key); ok { | 
					
						
							|  |  |  |  | 				return result, true | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 	return nil, false | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | func searchHost(headers any) string { | 
					
						
							|  |  |  |  | 	data, _ := headers.(map[string]any) | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 	for k, v := range data { | 
					
						
							|  |  |  |  | 		if strings.EqualFold(k, "host") { | 
					
						
							|  |  |  |  | 			switch v.(type) { | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 			case []any: | 
					
						
							|  |  |  |  | 				hosts, _ := v.([]any) | 
					
						
							| 
									
										
										
										
											2023-04-25 11:09:09 +00:00
										 |  |  |  | 				if len(hosts) > 0 { | 
					
						
							|  |  |  |  | 					return hosts[0].(string) | 
					
						
							|  |  |  |  | 				} else { | 
					
						
							|  |  |  |  | 					return "" | 
					
						
							|  |  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2025-03-12 19:13:51 +00:00
										 |  |  |  | 			case any: | 
					
						
							| 
									
										
										
										
											2023-04-09 19:43:18 +00:00
										 |  |  |  | 				return v.(string) | 
					
						
							|  |  |  |  | 			} | 
					
						
							|  |  |  |  | 		} | 
					
						
							|  |  |  |  | 	} | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 	return "" | 
					
						
							|  |  |  |  | } |