github.com/laof/lite-speed-test@v0.0.0-20230930011949-1f39b7037845/config/parser.go (about)

     1  package config
     2  
     3  import (
     4  	"encoding/base64"
     5  	"encoding/json"
     6  	"fmt"
     7  	"net"
     8  	"net/url"
     9  	"strconv"
    10  	"strings"
    11  
    12  	"github.com/laof/lite-speed-test/common/structure"
    13  	"github.com/laof/lite-speed-test/outbound"
    14  )
    15  
    16  func ParseProxy(mapping map[string]interface{}, namePrefix string) (string, error) {
    17  	decoder := structure.NewDecoder(structure.Option{TagName: "proxy", WeaklyTypedInput: true})
    18  	proxyType, existType := mapping["type"].(string)
    19  	if !existType {
    20  		return "", fmt.Errorf("missing type")
    21  	}
    22  
    23  	var (
    24  		err  error
    25  		link string
    26  	)
    27  
    28  	switch proxyType {
    29  	case "ss":
    30  		ssOption := &outbound.ShadowSocksOption{}
    31  		err = decoder.Decode(mapping, ssOption)
    32  		if err != nil {
    33  			break
    34  		}
    35  		auth := fmt.Sprintf("%s:%s", ssOption.Cipher, ssOption.Password)
    36  		link = fmt.Sprintf("ss://%s@%s", base64.StdEncoding.EncodeToString([]byte(auth)), net.JoinHostPort(ssOption.Server, strconv.Itoa(ssOption.Port)))
    37  		if len(ssOption.Name) > 0 {
    38  			link = fmt.Sprintf("%s#%s", link, url.QueryEscape(ssOption.Name))
    39  		}
    40  	case "ssr":
    41  		ssrOption := &outbound.ShadowSocksROption{}
    42  		err = decoder.Decode(mapping, ssrOption)
    43  		if err != nil {
    44  			break
    45  		}
    46  		password := base64.StdEncoding.EncodeToString([]byte(ssrOption.Password))
    47  		link = fmt.Sprintf("%s:%s:%s:%s:%s", net.JoinHostPort(ssrOption.Server, strconv.Itoa(ssrOption.Port)), ssrOption.Protocol, ssrOption.Cipher, ssrOption.Obfs, password)
    48  		remarks := base64.StdEncoding.EncodeToString([]byte(ssrOption.Name))
    49  
    50  		obfsParam := base64.StdEncoding.EncodeToString([]byte(ssrOption.ObfsParam))
    51  		protocolParam := base64.StdEncoding.EncodeToString([]byte(ssrOption.ProtocolParam))
    52  		link = fmt.Sprintf("%s/?obfsparam=%s&remarks=%s&protoparam=%s", link, url.QueryEscape(obfsParam), url.QueryEscape(remarks), url.QueryEscape(protocolParam))
    53  		link = fmt.Sprintf("ssr://%s", base64.StdEncoding.EncodeToString([]byte(link)))
    54  	case "vmess":
    55  		// TODO: h2
    56  		vmessOption := &outbound.VmessOption{
    57  			HTTPOpts: outbound.HTTPOptions{
    58  				Method: "GET",
    59  				Path:   []string{"/"},
    60  			},
    61  		}
    62  		err = decoder.Decode(mapping, vmessOption)
    63  		if err != nil {
    64  			break
    65  		}
    66  		tls := ""
    67  		if vmessOption.TLS {
    68  			tls = "tls"
    69  		}
    70  		if len(vmessOption.WSPath) == 0 && len(vmessOption.WSOpts.Path) > 0 {
    71  			vmessOption.WSPath = vmessOption.WSOpts.Path
    72  		}
    73  		host := ""
    74  		if h, ok := vmessOption.WSHeaders["Host"]; ok {
    75  			host = h
    76  		} else {
    77  			headers := vmessOption.WSOpts.Headers
    78  			if h, ok := headers["Host"]; ok {
    79  				host = h
    80  			}
    81  		}
    82  		if len(vmessOption.Network) < 1 {
    83  			vmessOption.Network = "tcp"
    84  		}
    85  		if len(vmessOption.Cipher) < 1 {
    86  			vmessOption.Cipher = "none"
    87  		}
    88  		skipCertVerify := vmessOption.SkipCertVerify
    89  		if len(vmessOption.ServerName) < 1 {
    90  			skipCertVerify = true
    91  		}
    92  		id := vmessOption.UUID
    93  		if len(id) < 1 {
    94  			id = vmessOption.Password
    95  		}
    96  		c := VmessConfigMarshal{
    97  			Ps:             namePrefix + vmessOption.Name,
    98  			Add:            vmessOption.Server,
    99  			Port:           vmessOption.Port,
   100  			Aid:            vmessOption.AlterID,
   101  			ID:             id,
   102  			Type:           vmessOption.Cipher,
   103  			TLS:            tls,
   104  			Net:            vmessOption.Network,
   105  			Path:           vmessOption.WSPath,
   106  			Host:           host,
   107  			SkipCertVerify: skipCertVerify,
   108  			ServerName:     vmessOption.ServerName,
   109  			Security:       vmessOption.Cipher,
   110  		}
   111  		data, err := json.MarshalIndent(&c, "", "    ")
   112  		if err != nil {
   113  			return "", err
   114  		}
   115  		link = fmt.Sprintf("vmess://%s", base64.StdEncoding.EncodeToString(data))
   116  	case "trojan":
   117  		trojanOption := &outbound.TrojanOption{}
   118  		err = decoder.Decode(mapping, trojanOption)
   119  		if err != nil {
   120  			break
   121  		}
   122  
   123  		link = fmt.Sprintf("trojan://%s@%s", trojanOption.Password, net.JoinHostPort(trojanOption.Server, strconv.Itoa(trojanOption.Port)))
   124  		query := []string{}
   125  		// allowInsecure
   126  		if trojanOption.SkipCertVerify {
   127  			query = append(query, "allowInsecure=1")
   128  		} else {
   129  			query = append(query, "security=tls")
   130  		}
   131  		if len(trojanOption.SNI) > 0 {
   132  			query = append(query, fmt.Sprintf("sni=%s", trojanOption.SNI))
   133  		}
   134  		// ws query
   135  		if trojanOption.Network == "ws" {
   136  			query = append(query, "type=ws")
   137  			if len(trojanOption.WSOpts.Path) > 0 {
   138  				query = append(query, fmt.Sprintf("path=%s", trojanOption.WSOpts.Path))
   139  				for k, v := range trojanOption.WSOpts.Headers {
   140  					query = append(query, fmt.Sprintf("%s=%s", k, v))
   141  				}
   142  			}
   143  		}
   144  		// grpc
   145  		if trojanOption.Network == "grpc" {
   146  			query = append(query, "type=grpc")
   147  			if len(trojanOption.GrpcOpts.GrpcServiceName) > 0 {
   148  				query = append(query, fmt.Sprintf("serviceName=%s", trojanOption.GrpcOpts.GrpcServiceName))
   149  			}
   150  		}
   151  
   152  		if len(query) > 0 {
   153  			link = fmt.Sprintf("%s?%s", link, strings.Join(query, "&"))
   154  		}
   155  		if len(trojanOption.Remarks) > 0 {
   156  			link = fmt.Sprintf("%s#%s%s", link, namePrefix, url.QueryEscape(trojanOption.Remarks))
   157  		}
   158  		if len(trojanOption.Name) > 0 {
   159  			link = fmt.Sprintf("%s#%s%s", link, namePrefix, url.QueryEscape(trojanOption.Name))
   160  		}
   161  	case "http":
   162  		httpOption := &outbound.HttpOption{}
   163  		err = decoder.Decode(mapping, httpOption)
   164  		if err != nil {
   165  			break
   166  		}
   167  		link = fmt.Sprintf("http://%s@%s", httpOption.Password, net.JoinHostPort(httpOption.Server, strconv.Itoa(httpOption.Port)))
   168  		query := []string{}
   169  		query = append(query, fmt.Sprintf("tls=%t", httpOption.TLS))
   170  		if len(httpOption.UserName) > 0 {
   171  			query = append(query, fmt.Sprintf("username=%s", httpOption.UserName))
   172  		}
   173  		// allowInsecure
   174  		if httpOption.SkipCertVerify {
   175  			query = append(query, "allowInsecure=1")
   176  		}
   177  		if len(httpOption.SNI) > 0 {
   178  			query = append(query, fmt.Sprintf("sni=%s", httpOption.SNI))
   179  		}
   180  		if len(query) > 0 {
   181  			link = fmt.Sprintf("%s?%s", link, strings.Join(query, "&"))
   182  		}
   183  		if len(httpOption.Name) > 0 {
   184  			link = fmt.Sprintf("%s#%s%s", link, namePrefix, url.QueryEscape(httpOption.Name))
   185  		}
   186  	default:
   187  		return "", fmt.Errorf("unsupport proxy type: %s", proxyType)
   188  	}
   189  
   190  	if err != nil {
   191  		return "", err
   192  	}
   193  
   194  	return link, nil
   195  
   196  }