Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/MHSanaei/3x-ui.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'sub/subService.go')
-rw-r--r--sub/subService.go709
1 files changed, 709 insertions, 0 deletions
diff --git a/sub/subService.go b/sub/subService.go
new file mode 100644
index 00000000..fc68b797
--- /dev/null
+++ b/sub/subService.go
@@ -0,0 +1,709 @@
+package sub
+
+import (
+ "encoding/base64"
+ "fmt"
+ "net/url"
+ "strings"
+ "x-ui/database"
+ "x-ui/database/model"
+ "x-ui/logger"
+ "x-ui/web/service"
+ "x-ui/xray"
+
+ "github.com/goccy/go-json"
+)
+
+type SubService struct {
+ address string
+ inboundService service.InboundService
+ settingServics service.SettingService
+}
+
+func (s *SubService) GetSubs(subId string, host string) ([]string, []string, error) {
+ s.address = host
+ var result []string
+ var headers []string
+ var traffic xray.ClientTraffic
+ var clientTraffics []xray.ClientTraffic
+ inbounds, err := s.getInboundsBySubId(subId)
+ if err != nil {
+ return nil, nil, err
+ }
+ for _, inbound := range inbounds {
+ clients, err := s.inboundService.GetClients(inbound)
+ if err != nil {
+ logger.Error("SubService - GetSub: Unable to get clients from inbound")
+ }
+ if clients == nil {
+ continue
+ }
+ for _, client := range clients {
+ if client.Enable && client.SubID == subId {
+ link := s.getLink(inbound, client.Email)
+ result = append(result, link)
+ clientTraffics = append(clientTraffics, s.getClientTraffics(inbound.ClientStats, client.Email))
+ }
+ }
+ }
+ 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
+ }
+ }
+ }
+ headers = append(headers, fmt.Sprintf("upload=%d; download=%d; total=%d; expire=%d", traffic.Up, traffic.Down, traffic.Total, traffic.ExpiryTime/1000))
+ updateInterval, _ := s.settingServics.GetSubUpdates()
+ headers = append(headers, fmt.Sprintf("%d", updateInterval))
+ headers = append(headers, subId)
+ return result, headers, nil
+}
+
+func (s *SubService) getInboundsBySubId(subId string) ([]*model.Inbound, error) {
+ db := database.GetDB()
+ var inbounds []*model.Inbound
+ err := db.Model(model.Inbound{}).Preload("ClientStats").Where("settings like ? and enable = ?", fmt.Sprintf(`%%"subId": "%s"%%`, subId), true).Find(&inbounds).Error
+ if err != nil {
+ return nil, err
+ }
+ return inbounds, nil
+}
+
+func (s *SubService) getClientTraffics(traffics []xray.ClientTraffic, email string) xray.ClientTraffic {
+ for _, traffic := range traffics {
+ if traffic.Email == email {
+ return traffic
+ }
+ }
+ return xray.ClientTraffic{}
+}
+
+func (s *SubService) getLink(inbound *model.Inbound, email string) string {
+ switch inbound.Protocol {
+ case "vmess":
+ return s.genVmessLink(inbound, email)
+ case "vless":
+ return s.genVlessLink(inbound, email)
+ case "trojan":
+ return s.genTrojanLink(inbound, email)
+ case "shadowsocks":
+ return s.genShadowsocksLink(inbound, email)
+ }
+ return ""
+}
+
+func (s *SubService) genVmessLink(inbound *model.Inbound, email string) string {
+ if inbound.Protocol != model.VMess {
+ return ""
+ }
+ remark := fmt.Sprintf("%s-%s", inbound.Remark, email)
+ obj := map[string]interface{}{
+ "v": "2",
+ "ps": remark,
+ "add": s.address,
+ "port": inbound.Port,
+ "type": "none",
+ }
+ var stream map[string]interface{}
+ json.Unmarshal([]byte(inbound.StreamSettings), &stream)
+ network, _ := stream["network"].(string)
+ obj["net"] = network
+ switch network {
+ case "tcp":
+ tcp, _ := stream["tcpSettings"].(map[string]interface{})
+ header, _ := tcp["header"].(map[string]interface{})
+ typeStr, _ := header["type"].(string)
+ obj["type"] = typeStr
+ if typeStr == "http" {
+ request := header["request"].(map[string]interface{})
+ requestPath, _ := request["path"].([]interface{})
+ obj["path"] = requestPath[0].(string)
+ headers, _ := request["headers"].(map[string]interface{})
+ obj["host"] = searchHost(headers)
+ }
+ case "kcp":
+ kcp, _ := stream["kcpSettings"].(map[string]interface{})
+ header, _ := kcp["header"].(map[string]interface{})
+ obj["type"], _ = header["type"].(string)
+ obj["path"], _ = kcp["seed"].(string)
+ case "ws":
+ ws, _ := stream["wsSettings"].(map[string]interface{})
+ obj["path"] = ws["path"].(string)
+ headers, _ := ws["headers"].(map[string]interface{})
+ obj["host"] = searchHost(headers)
+ case "http":
+ obj["net"] = "h2"
+ http, _ := stream["httpSettings"].(map[string]interface{})
+ obj["path"], _ = http["path"].(string)
+ obj["host"] = searchHost(http)
+ case "quic":
+ quic, _ := stream["quicSettings"].(map[string]interface{})
+ header := quic["header"].(map[string]interface{})
+ obj["type"], _ = header["type"].(string)
+ obj["host"], _ = quic["security"].(string)
+ obj["path"], _ = quic["key"].(string)
+ case "grpc":
+ grpc, _ := stream["grpcSettings"].(map[string]interface{})
+ obj["path"] = grpc["serviceName"].(string)
+ if grpc["multiMode"].(bool) {
+ obj["type"] = "multi"
+ }
+ }
+
+ security, _ := stream["security"].(string)
+ var domains []interface{}
+ obj["tls"] = security
+ if security == "tls" {
+ tlsSetting, _ := stream["tlsSettings"].(map[string]interface{})
+ alpns, _ := tlsSetting["alpn"].([]interface{})
+ if len(alpns) > 0 {
+ var alpn []string
+ for _, a := range alpns {
+ alpn = append(alpn, a.(string))
+ }
+ obj["alpn"] = strings.Join(alpn, ",")
+ }
+ tlsSettings, _ := searchKey(tlsSetting, "settings")
+ if tlsSetting != nil {
+ if sniValue, ok := searchKey(tlsSettings, "serverName"); ok {
+ obj["sni"], _ = sniValue.(string)
+ }
+ if fpValue, ok := searchKey(tlsSettings, "fingerprint"); ok {
+ obj["fp"], _ = fpValue.(string)
+ }
+ if insecure, ok := searchKey(tlsSettings, "allowInsecure"); ok {
+ obj["allowInsecure"], _ = insecure.(bool)
+ }
+ if domainSettings, ok := searchKey(tlsSettings, "domains"); ok {
+ domains, _ = domainSettings.([]interface{})
+ }
+ }
+ serverName, _ := tlsSetting["serverName"].(string)
+ if serverName != "" {
+ obj["add"] = serverName
+ }
+ }
+
+ clients, _ := s.inboundService.GetClients(inbound)
+ clientIndex := -1
+ for i, client := range clients {
+ if client.Email == email {
+ clientIndex = i
+ break
+ }
+ }
+ obj["id"] = clients[clientIndex].ID
+ obj["aid"] = clients[clientIndex].AlterIds
+
+ if len(domains) > 0 {
+ links := ""
+ for index, d := range domains {
+ domain := d.(map[string]interface{})
+ obj["ps"] = remark + "-" + domain["remark"].(string)
+ obj["add"] = domain["domain"].(string)
+ if index > 0 {
+ links += "\n"
+ }
+ jsonStr, _ := json.MarshalIndent(obj, "", " ")
+ links += "vmess://" + base64.StdEncoding.EncodeToString(jsonStr)
+ }
+ return links
+ }
+
+ jsonStr, _ := json.MarshalIndent(obj, "", " ")
+ return "vmess://" + base64.StdEncoding.EncodeToString(jsonStr)
+}
+
+func (s *SubService) genVlessLink(inbound *model.Inbound, email string) string {
+ address := s.address
+ if inbound.Protocol != model.VLESS {
+ return ""
+ }
+ var stream map[string]interface{}
+ json.Unmarshal([]byte(inbound.StreamSettings), &stream)
+ clients, _ := s.inboundService.GetClients(inbound)
+ 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":
+ tcp, _ := stream["tcpSettings"].(map[string]interface{})
+ header, _ := tcp["header"].(map[string]interface{})
+ typeStr, _ := header["type"].(string)
+ if typeStr == "http" {
+ request := header["request"].(map[string]interface{})
+ requestPath, _ := request["path"].([]interface{})
+ params["path"] = requestPath[0].(string)
+ headers, _ := request["headers"].(map[string]interface{})
+ params["host"] = searchHost(headers)
+ params["headerType"] = "http"
+ }
+ case "kcp":
+ kcp, _ := stream["kcpSettings"].(map[string]interface{})
+ header, _ := kcp["header"].(map[string]interface{})
+ params["headerType"] = header["type"].(string)
+ params["seed"] = kcp["seed"].(string)
+ case "ws":
+ ws, _ := stream["wsSettings"].(map[string]interface{})
+ params["path"] = ws["path"].(string)
+ headers, _ := ws["headers"].(map[string]interface{})
+ params["host"] = searchHost(headers)
+ case "http":
+ http, _ := stream["httpSettings"].(map[string]interface{})
+ params["path"] = http["path"].(string)
+ params["host"] = searchHost(http)
+ case "quic":
+ quic, _ := stream["quicSettings"].(map[string]interface{})
+ params["quicSecurity"] = quic["security"].(string)
+ params["key"] = quic["key"].(string)
+ header := quic["header"].(map[string]interface{})
+ params["headerType"] = header["type"].(string)
+ case "grpc":
+ grpc, _ := stream["grpcSettings"].(map[string]interface{})
+ params["serviceName"] = grpc["serviceName"].(string)
+ if grpc["multiMode"].(bool) {
+ params["mode"] = "multi"
+ }
+ }
+
+ security, _ := stream["security"].(string)
+ var domains []interface{}
+ if security == "tls" {
+ params["security"] = "tls"
+ tlsSetting, _ := stream["tlsSettings"].(map[string]interface{})
+ alpns, _ := tlsSetting["alpn"].([]interface{})
+ var alpn []string
+ for _, a := range alpns {
+ alpn = append(alpn, a.(string))
+ }
+ if len(alpn) > 0 {
+ params["alpn"] = strings.Join(alpn, ",")
+ }
+ tlsSettings, _ := searchKey(tlsSetting, "settings")
+ if tlsSetting != nil {
+ if sniValue, ok := searchKey(tlsSettings, "serverName"); ok {
+ params["sni"], _ = sniValue.(string)
+ }
+ 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 domainSettings, ok := searchKey(tlsSettings, "domains"); ok {
+ domains, _ = domainSettings.([]interface{})
+ }
+ }
+
+ if streamNetwork == "tcp" && len(clients[clientIndex].Flow) > 0 {
+ params["flow"] = clients[clientIndex].Flow
+ }
+
+ serverName, _ := tlsSetting["serverName"].(string)
+ if serverName != "" {
+ address = serverName
+ }
+ }
+
+ if security == "reality" {
+ params["security"] = "reality"
+ realitySetting, _ := stream["realitySettings"].(map[string]interface{})
+ realitySettings, _ := searchKey(realitySetting, "settings")
+ if realitySetting != nil {
+ if sniValue, ok := searchKey(realitySetting, "serverNames"); ok {
+ sNames, _ := sniValue.([]interface{})
+ params["sni"], _ = sNames[0].(string)
+ }
+ if pbkValue, ok := searchKey(realitySettings, "publicKey"); ok {
+ params["pbk"], _ = pbkValue.(string)
+ }
+ if sidValue, ok := searchKey(realitySetting, "shortIds"); ok {
+ shortIds, _ := sidValue.([]interface{})
+ params["sid"], _ = shortIds[0].(string)
+ }
+ if fpValue, ok := searchKey(realitySettings, "fingerprint"); ok {
+ if fp, ok := fpValue.(string); ok && len(fp) > 0 {
+ params["fp"] = fp
+ }
+ }
+ if spxValue, ok := searchKey(realitySettings, "spiderX"); ok {
+ if spx, ok := spxValue.(string); ok && len(spx) > 0 {
+ params["spx"] = spx
+ }
+ }
+ if serverName, ok := searchKey(realitySettings, "serverName"); ok {
+ if sname, ok := serverName.(string); ok && len(sname) > 0 {
+ address = sname
+ }
+ }
+ }
+
+ if streamNetwork == "tcp" && len(clients[clientIndex].Flow) > 0 {
+ params["flow"] = clients[clientIndex].Flow
+ }
+ }
+
+ if security == "xtls" {
+ params["security"] = "xtls"
+ xtlsSetting, _ := stream["xtlsSettings"].(map[string]interface{})
+ alpns, _ := xtlsSetting["alpn"].([]interface{})
+ var alpn []string
+ for _, a := range alpns {
+ alpn = append(alpn, a.(string))
+ }
+ if len(alpn) > 0 {
+ params["alpn"] = strings.Join(alpn, ",")
+ }
+
+ xtlsSettings, _ := searchKey(xtlsSetting, "settings")
+ if xtlsSetting != nil {
+ if fpValue, ok := searchKey(xtlsSettings, "fingerprint"); ok {
+ params["fp"], _ = fpValue.(string)
+ }
+ if insecure, ok := searchKey(xtlsSettings, "allowInsecure"); ok {
+ if insecure.(bool) {
+ params["allowInsecure"] = "1"
+ }
+ }
+ if sniValue, ok := searchKey(xtlsSettings, "serverName"); ok {
+ params["sni"], _ = sniValue.(string)
+ }
+ }
+
+ if streamNetwork == "tcp" && len(clients[clientIndex].Flow) > 0 {
+ params["flow"] = clients[clientIndex].Flow
+ }
+
+ serverName, _ := xtlsSetting["serverName"].(string)
+ if serverName != "" {
+ address = serverName
+ }
+ }
+
+ 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()
+
+ remark := fmt.Sprintf("%s-%s", inbound.Remark, email)
+
+ if len(domains) > 0 {
+ links := ""
+ for index, d := range domains {
+ domain := d.(map[string]interface{})
+ url.Fragment = remark + "-" + domain["remark"].(string)
+ url.Host = fmt.Sprintf("%s:%d", domain["domain"].(string), port)
+ if index > 0 {
+ links += "\n"
+ }
+ links += url.String()
+ }
+ return links
+ }
+ url.Fragment = remark
+ return url.String()
+}
+
+func (s *SubService) genTrojanLink(inbound *model.Inbound, email string) string {
+ address := s.address
+ if inbound.Protocol != model.Trojan {
+ return ""
+ }
+ var stream map[string]interface{}
+ json.Unmarshal([]byte(inbound.StreamSettings), &stream)
+ clients, _ := s.inboundService.GetClients(inbound)
+ 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":
+ tcp, _ := stream["tcpSettings"].(map[string]interface{})
+ header, _ := tcp["header"].(map[string]interface{})
+ typeStr, _ := header["type"].(string)
+ if typeStr == "http" {
+ request := header["request"].(map[string]interface{})
+ requestPath, _ := request["path"].([]interface{})
+ params["path"] = requestPath[0].(string)
+ headers, _ := request["headers"].(map[string]interface{})
+ params["host"] = searchHost(headers)
+ params["headerType"] = "http"
+ }
+ case "kcp":
+ kcp, _ := stream["kcpSettings"].(map[string]interface{})
+ header, _ := kcp["header"].(map[string]interface{})
+ params["headerType"] = header["type"].(string)
+ params["seed"] = kcp["seed"].(string)
+ case "ws":
+ ws, _ := stream["wsSettings"].(map[string]interface{})
+ params["path"] = ws["path"].(string)
+ headers, _ := ws["headers"].(map[string]interface{})
+ params["host"] = searchHost(headers)
+ case "http":
+ http, _ := stream["httpSettings"].(map[string]interface{})
+ params["path"] = http["path"].(string)
+ params["host"] = searchHost(http)
+ case "quic":
+ quic, _ := stream["quicSettings"].(map[string]interface{})
+ params["quicSecurity"] = quic["security"].(string)
+ params["key"] = quic["key"].(string)
+ header := quic["header"].(map[string]interface{})
+ params["headerType"] = header["type"].(string)
+ case "grpc":
+ grpc, _ := stream["grpcSettings"].(map[string]interface{})
+ params["serviceName"] = grpc["serviceName"].(string)
+ if grpc["multiMode"].(bool) {
+ params["mode"] = "multi"
+ }
+ }
+
+ security, _ := stream["security"].(string)
+ var domains []interface{}
+ if security == "tls" {
+ params["security"] = "tls"
+ tlsSetting, _ := stream["tlsSettings"].(map[string]interface{})
+ alpns, _ := tlsSetting["alpn"].([]interface{})
+ var alpn []string
+ for _, a := range alpns {
+ alpn = append(alpn, a.(string))
+ }
+ if len(alpn) > 0 {
+ params["alpn"] = strings.Join(alpn, ",")
+ }
+ tlsSettings, _ := searchKey(tlsSetting, "settings")
+ if tlsSetting != nil {
+ if sniValue, ok := searchKey(tlsSettings, "serverName"); ok {
+ params["sni"], _ = sniValue.(string)
+ }
+ 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 domainSettings, ok := searchKey(tlsSettings, "domains"); ok {
+ domains, _ = domainSettings.([]interface{})
+ }
+ }
+
+ serverName, _ := tlsSetting["serverName"].(string)
+ if serverName != "" {
+ address = serverName
+ }
+ }
+
+ if security == "reality" {
+ params["security"] = "reality"
+ realitySetting, _ := stream["realitySettings"].(map[string]interface{})
+ realitySettings, _ := searchKey(realitySetting, "settings")
+ if realitySetting != nil {
+ if sniValue, ok := searchKey(realitySetting, "serverNames"); ok {
+ sNames, _ := sniValue.([]interface{})
+ params["sni"], _ = sNames[0].(string)
+ }
+ if pbkValue, ok := searchKey(realitySettings, "publicKey"); ok {
+ params["pbk"], _ = pbkValue.(string)
+ }
+ if sidValue, ok := searchKey(realitySettings, "shortIds"); ok {
+ shortIds, _ := sidValue.([]interface{})
+ params["sid"], _ = shortIds[0].(string)
+ }
+ if fpValue, ok := searchKey(realitySettings, "fingerprint"); ok {
+ if fp, ok := fpValue.(string); ok && len(fp) > 0 {
+ params["fp"] = fp
+ }
+ }
+ if spxValue, ok := searchKey(realitySettings, "spiderX"); ok {
+ if spx, ok := spxValue.(string); ok && len(spx) > 0 {
+ params["spx"] = spx
+ }
+ }
+ if serverName, ok := searchKey(realitySettings, "serverName"); ok {
+ if sname, ok := serverName.(string); ok && len(sname) > 0 {
+ address = sname
+ }
+ }
+ }
+
+ if streamNetwork == "tcp" && len(clients[clientIndex].Flow) > 0 {
+ params["flow"] = clients[clientIndex].Flow
+ }
+ }
+
+ if security == "xtls" {
+ params["security"] = "xtls"
+ xtlsSetting, _ := stream["xtlsSettings"].(map[string]interface{})
+ alpns, _ := xtlsSetting["alpn"].([]interface{})
+ var alpn []string
+ for _, a := range alpns {
+ alpn = append(alpn, a.(string))
+ }
+ if len(alpn) > 0 {
+ params["alpn"] = strings.Join(alpn, ",")
+ }
+
+ xtlsSettings, _ := searchKey(xtlsSetting, "settings")
+ if xtlsSetting != nil {
+ if fpValue, ok := searchKey(xtlsSettings, "fingerprint"); ok {
+ params["fp"], _ = fpValue.(string)
+ }
+ if insecure, ok := searchKey(xtlsSettings, "allowInsecure"); ok {
+ if insecure.(bool) {
+ params["allowInsecure"] = "1"
+ }
+ }
+ if sniValue, ok := searchKey(xtlsSettings, "serverName"); ok {
+ params["sni"], _ = sniValue.(string)
+ }
+ }
+
+ if streamNetwork == "tcp" && len(clients[clientIndex].Flow) > 0 {
+ params["flow"] = clients[clientIndex].Flow
+ }
+
+ serverName, _ := xtlsSetting["serverName"].(string)
+ if serverName != "" {
+ address = serverName
+ }
+ }
+
+ 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()
+
+ remark := fmt.Sprintf("%s-%s", inbound.Remark, email)
+
+ if len(domains) > 0 {
+ links := ""
+ for index, d := range domains {
+ domain := d.(map[string]interface{})
+ url.Fragment = remark + "-" + domain["remark"].(string)
+ url.Host = fmt.Sprintf("%s:%d", domain["domain"].(string), port)
+ if index > 0 {
+ links += "\n"
+ }
+ links += url.String()
+ }
+ return links
+ }
+
+ url.Fragment = remark
+ return url.String()
+}
+
+func (s *SubService) genShadowsocksLink(inbound *model.Inbound, email string) string {
+ address := s.address
+ if inbound.Protocol != model.Shadowsocks {
+ return ""
+ }
+ clients, _ := s.inboundService.GetClients(inbound)
+
+ var settings map[string]interface{}
+ 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
+ }
+ }
+ encPart := fmt.Sprintf("%s:%s:%s", method, inboundPassword, clients[clientIndex].Password)
+ remark := fmt.Sprintf("%s-%s", inbound.Remark, clients[clientIndex].Email)
+ return fmt.Sprintf("ss://%s@%s:%d#%s", base64.StdEncoding.EncodeToString([]byte(encPart)), address, inbound.Port, remark)
+}
+
+func searchKey(data interface{}, key string) (interface{}, bool) {
+ switch val := data.(type) {
+ case map[string]interface{}:
+ for k, v := range val {
+ if k == key {
+ return v, true
+ }
+ if result, ok := searchKey(v, key); ok {
+ return result, true
+ }
+ }
+ case []interface{}:
+ for _, v := range val {
+ if result, ok := searchKey(v, key); ok {
+ return result, true
+ }
+ }
+ }
+ return nil, false
+}
+
+func searchHost(headers interface{}) string {
+ data, _ := headers.(map[string]interface{})
+ for k, v := range data {
+ if strings.EqualFold(k, "host") {
+ switch v.(type) {
+ case []interface{}:
+ hosts, _ := v.([]interface{})
+ if len(hosts) > 0 {
+ return hosts[0].(string)
+ } else {
+ return ""
+ }
+ case interface{}:
+ return v.(string)
+ }
+ }
+ }
+
+ return ""
+}