130 lines
3.2 KiB
Go
130 lines
3.2 KiB
Go
package convert
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"net/url"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
func handleVShareLink(names map[string]int, url *url.URL, scheme string, proxy map[string]any) error {
|
|
// Xray VMessAEAD / VLESS share link standard
|
|
// https://github.com/XTLS/Xray-core/discussions/716
|
|
query := url.Query()
|
|
proxy["name"] = uniqueName(names, url.Fragment)
|
|
if url.Hostname() == "" {
|
|
return errors.New("url.Hostname() is empty")
|
|
}
|
|
if url.Port() == "" {
|
|
return errors.New("url.Port() is empty")
|
|
}
|
|
proxy["type"] = scheme
|
|
proxy["server"] = url.Hostname()
|
|
proxy["port"] = url.Port()
|
|
proxy["uuid"] = url.User.Username()
|
|
proxy["udp"] = true
|
|
tls := strings.ToLower(query.Get("security"))
|
|
if strings.HasSuffix(tls, "tls") || tls == "reality" {
|
|
proxy["tls"] = true
|
|
if fingerprint := query.Get("fp"); fingerprint == "" {
|
|
proxy["client-fingerprint"] = "chrome"
|
|
} else {
|
|
proxy["client-fingerprint"] = fingerprint
|
|
}
|
|
if alpn := query.Get("alpn"); alpn != "" {
|
|
proxy["alpn"] = strings.Split(alpn, ",")
|
|
}
|
|
}
|
|
if sni := query.Get("sni"); sni != "" {
|
|
proxy["servername"] = sni
|
|
}
|
|
if realityPublicKey := query.Get("pbk"); realityPublicKey != "" {
|
|
proxy["reality-opts"] = map[string]any{
|
|
"public-key": realityPublicKey,
|
|
"short-id": query.Get("sid"),
|
|
}
|
|
}
|
|
|
|
switch query.Get("packetEncoding") {
|
|
case "none":
|
|
case "packet":
|
|
proxy["packet-addr"] = true
|
|
default:
|
|
proxy["xudp"] = true
|
|
}
|
|
|
|
network := strings.ToLower(query.Get("type"))
|
|
if network == "" {
|
|
network = "tcp"
|
|
}
|
|
fakeType := strings.ToLower(query.Get("headerType"))
|
|
if fakeType == "http" {
|
|
network = "http"
|
|
} else if network == "http" {
|
|
network = "h2"
|
|
}
|
|
proxy["network"] = network
|
|
switch network {
|
|
case "tcp":
|
|
if fakeType != "none" {
|
|
headers := make(map[string]any)
|
|
httpOpts := make(map[string]any)
|
|
httpOpts["path"] = []string{"/"}
|
|
|
|
if host := query.Get("host"); host != "" {
|
|
headers["Host"] = []string{host}
|
|
}
|
|
|
|
if method := query.Get("method"); method != "" {
|
|
httpOpts["method"] = method
|
|
}
|
|
|
|
if path := query.Get("path"); path != "" {
|
|
httpOpts["path"] = []string{path}
|
|
}
|
|
httpOpts["headers"] = headers
|
|
proxy["http-opts"] = httpOpts
|
|
}
|
|
|
|
case "http":
|
|
headers := make(map[string]any)
|
|
h2Opts := make(map[string]any)
|
|
h2Opts["path"] = []string{"/"}
|
|
if path := query.Get("path"); path != "" {
|
|
h2Opts["path"] = []string{path}
|
|
}
|
|
if host := query.Get("host"); host != "" {
|
|
h2Opts["host"] = []string{host}
|
|
}
|
|
h2Opts["headers"] = headers
|
|
proxy["h2-opts"] = h2Opts
|
|
|
|
case "ws":
|
|
headers := make(map[string]any)
|
|
wsOpts := make(map[string]any)
|
|
headers["User-Agent"] = RandUserAgent()
|
|
headers["Host"] = query.Get("host")
|
|
wsOpts["path"] = query.Get("path")
|
|
wsOpts["headers"] = headers
|
|
|
|
if earlyData := query.Get("ed"); earlyData != "" {
|
|
med, err := strconv.Atoi(earlyData)
|
|
if err != nil {
|
|
return fmt.Errorf("bad WebSocket max early data size: %v", err)
|
|
}
|
|
wsOpts["max-early-data"] = med
|
|
}
|
|
if earlyDataHeader := query.Get("eh"); earlyDataHeader != "" {
|
|
wsOpts["early-data-header-name"] = earlyDataHeader
|
|
}
|
|
|
|
proxy["ws-opts"] = wsOpts
|
|
|
|
case "grpc":
|
|
grpcOpts := make(map[string]any)
|
|
grpcOpts["grpc-service-name"] = query.Get("serviceName")
|
|
proxy["grpc-opts"] = grpcOpts
|
|
}
|
|
return nil
|
|
}
|