From ec6c2adf9bb69d22f78da10d0aa58148265b8d29 Mon Sep 17 00:00:00 2001 From: MystiPanda Date: Fri, 5 Jul 2024 22:44:05 +0800 Subject: [PATCH] chore: Improve URI parser --- src/services/types.d.ts | 470 +++++++++++++++++++++++++++++++--------- src/utils/uri-parser.ts | 183 ++++++++-------- 2 files changed, 459 insertions(+), 194 deletions(-) diff --git a/src/services/types.d.ts b/src/services/types.d.ts index 3f350101..d0f9c797 100644 --- a/src/services/types.d.ts +++ b/src/services/types.d.ts @@ -228,8 +228,373 @@ interface IProxyGroupConfig { icon?: string; } -interface IProxyConfig { - name: string; +interface WsOptions { + path?: string; + headers?: { + [key: string]: string; + }; + "max-early-data"?: number; + "early-data-header-name"?: string; + "v2ray-http-upgrade"?: boolean; + "v2ray-http-upgrade-fast-open"?: boolean; +} + +interface HttpOptions { + method?: string; + path?: string[]; + headers?: { + [key: string]: string; + }; +} + +interface GrpcOptions { + "grpc-service-name"?: string; +} +type NetworkType = "ws" | "http" | "h2" | "grpc"; + +// base +interface IProxyBaseConfig { + tfo?: boolean; + mptcp?: boolean; + "interface-name"?: string; + "routing-mark"?: number; + "ip-version"?: string; + "dialer-proxy"?: string; +} +// direct +interface IProxyDirectConfig extends IProxyBaseConfig { + name?: string; + type: "direct"; +} +// dns +interface IProxyDnsConfig extends IProxyBaseConfig { + name?: string; + type: "dns"; +} +// http +interface IProxyHttpConfig extends IProxyBaseConfig { + name?: string; + type: "http"; + server?: string; + port?: number; + username?: string; + password?: string; + tls?: boolean; + sni?: string; + "skip-cert-verify"?: boolean; + fingerprint?: string; + headers?: {}; +} +// socks5 +interface IProxySocks5Config extends IProxyBaseConfig { + name?: string; + type: "socks5"; + server?: string; + port?: number; + username?: string; + password?: string; + tls?: boolean; + udp?: boolean; + "skip-cert-verify"?: boolean; + fingerprint?: string; +} +// ssh +interface IProxySshConfig extends IProxyBaseConfig { + name?: string; + type: "ssh"; + server?: string; + port?: number; + username?: string; + password?: string; + "private-key"?: string; + "private-key-passphrase"?: string; + "host-key"?: string; + "host-key-algorithms"?: string; +} +// trojan +interface IProxyTrojanConfig extends IProxyBaseConfig { + name?: string; + type: "trojan"; + server?: string; + port?: number; + password?: string; + alpn?: string[]; + sni?: string; + "skip-cert-verify"?: boolean; + fingerprint?: string; + udp?: boolean; + network?: NetworkType; + "reality-opts"?: {}; + "grpc-opts"?: GrpcOptions; + "ws-opts"?: WsOptions; + "ss-opts"?: { + enabled?: boolean; + method?: string; + password?: string; + }; + "client-fingerprint"?: string; +} +// tuic +interface IProxyTuicConfig extends IProxyBaseConfig { + name?: string; + type: "tuic"; + server?: string; + port?: number; + token?: string; + uuid?: string; + password?: string; + ip?: string; + "heartbeat-interval"?: number; + alpn?: string[]; + "reduce-rtt"?: boolean; + "request-timeout"?: number; + "udp-relay-mode"?: string; + "congestion-controller"?: string; + "disable-sni"?: boolean; + "max-udp-relay-packet-size"?: number; + "fast-open"?: boolean; + "max-open-streams"?: number; + cwnd?: number; + "skip-cert-verify"?: boolean; + fingerprint?: string; + ca?: string; + "ca-str"?: string; + "recv-window-conn"?: number; + "recv-window"?: number; + "disable-mtu-discovery"?: boolean; + "max-datagram-frame-size"?: number; + sni?: string; + "udp-over-stream"?: boolean; + "udp-over-stream-version"?: number; +} +// vless +interface IProxyVlessConfig extends IProxyBaseConfig { + name?: string; + type: "vless"; + server?: string; + port?: number; + uuid?: string; + flow?: string; + tls?: boolean; + alpn?: string[]; + udp?: boolean; + "packet-addr"?: boolean; + xudp?: boolean; + "packet-encoding"?: string; + network?: NetworkType; + "reality-opts"?: { + "public-key"?: string; + "short-id"?: string; + }; + "http-opts"?: HttpOptions; + "h2-opts"?: {}; + "grpc-opts"?: GrpcOptions; + "ws-opts"?: WsOptions; + "ws-path"?: string; + "ws-headers"?: {}; + "skip-cert-verify"?: boolean; + fingerprint?: string; + servername?: string; + "client-fingerprint"?: string; +} +// vmess +interface IProxyVmessConfig extends IProxyBaseConfig { + name?: string; + type: "vmess"; + server?: string; + port?: number; + uuid?: string; + alterId?: number; + cipher?: string; + udp?: boolean; + network?: NetworkType; + tls?: boolean; + alpn?: string[]; + "skip-cert-verify"?: boolean; + fingerprint?: string; + servername?: string; + "reality-opts"?: {}; + "http-opts"?: HttpOptions; + "h2-opts"?: { + path?: string; + host?: string; + }; + "grpc-opts"?: GrpcOptions; + "ws-opts"?: WsOptions; + "packet-addr"?: boolean; + xudp?: boolean; + "packet-encoding"?: string; + "global-padding"?: boolean; + "authenticated-length"?: boolean; + "client-fingerprint"?: string; +} +interface WireGuardPeerOptions { + server?: string; + port?: number; + "public-key"?: string; + "pre-shared-key"?: string; + reserved?: number[]; + "allowed-ips"?: string[]; +} +// wireguard +interface IProxyWireguardConfig extends IProxyBaseConfig, WireGuardPeerOptions { + name?: string; + type: "wireguard"; + ip?: string; + ipv6?: string; + "private-key"?: string; + workers?: number; + mtu?: number; + udp?: boolean; + "persistent-keepalive"?: number; + peers?: WireGuardPeerOptions[]; + "remote-dns-resolve"?: boolean; + dns?: string[]; + "refresh-server-ip-interval"?: number; +} +// hysteria +interface IProxyHysteriaConfig extends IProxyBaseConfig { + name?: string; + type: "hysteria"; + server?: string; + port?: number; + ports?: string; + protocol?: string; + "obfs-protocol"?: string; + up?: string; + "up-speed"?: number; + down?: string; + "down-speed"?: number; + auth?: string; + "auth-str"?: string; + obfs?: string; + sni?: string; + "skip-cert-verify"?: boolean; + fingerprint?: string; + alpn?: string[]; + ca?: string; + "ca-str"?: string; + "recv-window-conn"?: number; + "recv-window"?: number; + "disable-mtu-discovery"?: boolean; + "fast-open"?: boolean; + "hop-interval"?: number; +} +// hysteria2 +interface IProxyHysteria2Config extends IProxyBaseConfig { + name?: string; + type: "hysteria2"; + server?: string; + port?: number; + ports?: string; + "hop-interval"?: number; + protocol?: string; + "obfs-protocol"?: string; + up?: string; + down?: string; + password?: string; + obfs?: string; + "obfs-password"?: string; + sni?: string; + "skip-cert-verify"?: boolean; + fingerprint?: string; + alpn?: string[]; + ca?: string; + "ca-str"?: string; + cwnd?: number; + "udp-mtu"?: number; +} +// shadowsocks +interface IProxyShadowsocksConfig extends IProxyBaseConfig { + name?: string; + type: "ss"; + server?: string; + port?: number; + password?: string; + cipher?: string; + udp?: boolean; + plugin?: string; + "plugin-opts"?: { + mode?: string; + host?: string; + password?: string; + path?: string; + tls?: string; + fingerprint?: string; + headers?: {}; + "skip-cert-verify"?: boolean; + version?: number; + mux?: boolean; + "v2ray-http-upgrade"?: boolean; + "v2ray-http-upgrade-fast-open"?: boolean; + "version-hint"?: string; + "restls-script"?: string; + }; + "udp-over-tcp"?: boolean; + "udp-over-tcp-version"?: number; + "client-fingerprint"?: string; +} +// shadowsocksR +interface IProxyshadowsocksRConfig extends IProxyBaseConfig { + name?: string; + type: "ssr"; + server?: string; + port?: number; + password?: string; + cipher?: string; + obfs?: string; + "obfs-param"?: string; + protocol?: string; + "protocol-param"?: string; + udp?: boolean; +} +// sing-mux +interface IProxySmuxConfig { + smux?: { + enabled?: boolean; + protocol?: string; + "max-connections"?: number; + "min-streams"?: number; + "max-streams"?: number; + padding?: boolean; + statistic?: boolean; + "only-tcp"?: boolean; + "brutal-opts"?: { + enabled?: boolean; + up?: string; + down?: string; + }; + }; +} +// snell +interface IProxySnellConfig extends IProxyBaseConfig { + name?: string; + type: "snell"; + server?: string; + port?: number; + psk?: string; + udp?: boolean; + version?: number; + "obfs-opts"?: {}; +} +interface IProxyConfig + extends IProxyBaseConfig, + IProxyDirectConfig, + IProxyDnsConfig, + IProxyHttpConfig, + IProxySocks5Config, + IProxySshConfig, + IProxyTrojanConfig, + IProxyTuicConfig, + IProxyVlessConfig, + IProxyVmessConfig, + IProxyWireguardConfig, + IProxyHysteriaConfig, + IProxyHysteria2Config, + IProxyShadowsocksConfig, + IProxyshadowsocksRConfig, + IProxySmuxConfig, + IProxySnellConfig { type: | "ss" | "ssr" @@ -246,107 +611,6 @@ interface IProxyConfig { | "socks5" | "vmess" | "vless"; - server: string; - port: number; - "ip-version"?: string; - udp?: boolean; - "interface-name"?: string; - "routing-mark"?: number; - tfo?: boolean; - mptcp?: boolean; - "dialer-proxy"?: string; - plugin?: "obfs" | "v2ray-plugin" | "shadow-tls" | "restls"; - "plugin-opts"?: { - mode?: string; - host?: string; - path?: string; - tls?: string; - }; - cipher?: string; - password?: string; - "udp-over-tcp"?: boolean; - protocol?: string; - obfs?: string; - "protocol-param"?: string; - "obfs-param"?: string; - uuid?: string; - tls?: boolean; - "skip-cert-verify"?: boolean; - network?: "ws" | "http" | "h2" | "grpc"; - "ws-opts"?: { - path?: string; - headers?: {}; - }; - alterId?: number; - sni?: string; - "http-opts"?: {}; - "grpc-opts"?: {}; - "ws-opts"?: {}; - "h2-opts"?: {}; - "reality-opts"?: { - "public-key"?: string; - "short-id"?: string; - }; - flow?: "xtls-rprx-vision"; - "client-fingerprint"?: - | "chrome" - | "firefox" - | "safari" - | "iOS" - | "android" - | "edge" - | "360" - | "qq" - | "random"; - alpn?: string[]; - ws?: { - headers?: { - Host?: string; - }; - "ws-service-name"?: string; - path?: string; - }; - http?: { - headers?: { - Host?: string; - }; - "http-service-name"?: string; - path?: string; - }; - grpc?: {}; - ports?: string; - "obfs-password"?: string; - "tls-fingerprint"?: string; - "auth-str"?: string; - up?: string; - down?: string; - "fast-open"?: boolean; - fingerprint?: string; - "disable-mtu-discovery"?: boolean; - ca?: string; - "ca-str"?: string; - "recv-window-conn"?: number; - "recv-window"?: number; - token?: string; - ip?: string; - "heartbeat-interval"?: number; - "disable-sni"?: boolean; - "reduce-rtt"?: boolean; - "request-timeout"?: number; - "udp-relay-mode"?: string; - "congestion-controller"?: string; - "max-udp-relay-packet-size"?: number; - "max-open-streams"?: number; - "private-key"?: string; - "public-key"?: string; - ipv6?: string; - reserved?: number[]; - mtu?: number; - "remote-dns-resolve"?: boolean; - "allowed-ips"?: string[]; - dns?: string[]; - "pre-shared-key"?: string; - username?: string; } interface IVergeConfig { diff --git a/src/utils/uri-parser.ts b/src/utils/uri-parser.ts index de9cfb83..6da07a60 100644 --- a/src/utils/uri-parser.ts +++ b/src/utils/uri-parser.ts @@ -51,6 +51,10 @@ function isPresent(value: any): boolean { return value !== null && value !== undefined; } +function trimStr(str: string | undefined): string | undefined { + return str ? str.trim() : str; +} + function isNotBlank(name: string) { return name.trim().length !== 0; } @@ -76,12 +80,12 @@ function decodeBase64OrOriginal(str: string): string { } } -function URI_SS(line: string): IProxyConfig { +function URI_SS(line: string): IProxyShadowsocksConfig { // parse url let content = line.split("ss://")[1]; - const proxy: IProxyConfig = { - name: decodeURIComponent(line.split("#")[1]), + const proxy: IProxyShadowsocksConfig = { + name: trimStr(decodeURIComponent(line.split("#")[1])), type: "ss", server: "", port: 0, @@ -168,7 +172,7 @@ function URI_SS(line: string): IProxyConfig { return proxy; } -function URI_SSR(line: string): IProxyConfig { +function URI_SSR(line: string): IProxyshadowsocksRConfig { line = decodeBase64OrOriginal(line.split("ssr://")[1]); // handle IPV6 & IPV4 format @@ -186,8 +190,8 @@ function URI_SSR(line: string): IProxyConfig { .substring(splitIdx + 1) .split("/?")[0] .split(":"); - let proxy: IProxyConfig = { - name: "", + let proxy: IProxyshadowsocksRConfig = { + name: "SSR", type: "ssr", server, port, @@ -210,7 +214,7 @@ function URI_SSR(line: string): IProxyConfig { proxy = { ...proxy, name: other_params.remarks - ? decodeBase64OrOriginal(other_params.remarks) + ? trimStr(decodeBase64OrOriginal(other_params.remarks)) : proxy.server, "protocol-param": getIfNotBlank( decodeBase64OrOriginal(other_params.protoparam || "").replace(/\s/g, "") @@ -222,7 +226,7 @@ function URI_SSR(line: string): IProxyConfig { return proxy; } -function URI_VMESS(line: string): IProxyConfig { +function URI_VMESS(line: string): IProxyVmessConfig { line = line.split("vmess://")[1]; let content = decodeBase64OrOriginal(line); console.log(content); @@ -238,8 +242,8 @@ function URI_VMESS(line: string): IProxyConfig { } } - const proxy: IProxyConfig = { - name: partitions[0].split("=")[0].trim(), + const proxy: IProxyVmessConfig = { + name: trimStr(partitions[0].split("=")[0]), type: "vmess", server: partitions[1], port: parseInt(partitions[2], 10), @@ -308,29 +312,30 @@ function URI_VMESS(line: string): IProxyConfig { } } } - console.log(params); + const server = params.add; const port = parseInt(getIfPresent(params.port), 10); - const proxy: IProxyConfig = { + const proxy: IProxyVmessConfig = { name: - params.ps ?? - params.remarks ?? - params.remark ?? + trimStr(params.ps) ?? + trimStr(params.remarks) ?? + trimStr(params.remark) ?? `VMess ${server}:${port}`, type: "vmess", server, port, cipher: getIfPresent(params.scy, "auto"), uuid: params.id, - alterId: parseInt(getIfPresent(params.aid ?? params.alterId, 0), 10), tls: ["tls", true, 1, "1"].includes(params.tls), "skip-cert-verify": isPresent(params.verify_cert) ? !params.verify_cert : undefined, }; + proxy.alterId = parseInt(getIfPresent(params.aid ?? params.alterId, 0), 10); + if (proxy.tls && params.sni) { - proxy.sni = params.sni; + proxy.servername = params.sni; } let httpupgrade = false; @@ -383,7 +388,6 @@ function URI_VMESS(line: string): IProxyConfig { if (["grpc"].includes(proxy.network)) { proxy[`grpc-opts`] = { "grpc-service-name": getIfNotBlank(transportPath), - "_grpc-type": getIfNotBlank(params.type), }; } else { const opts: Record = { @@ -400,8 +404,8 @@ function URI_VMESS(line: string): IProxyConfig { delete proxy.network; } - if (proxy.tls && !proxy.sni && transportHost) { - proxy.sni = transportHost; + if (proxy.tls && !proxy.servername && transportHost) { + proxy.servername = transportHost; } } @@ -409,7 +413,7 @@ function URI_VMESS(line: string): IProxyConfig { } } -function URI_VLESS(line: string): IProxyConfig { +function URI_VLESS(line: string): IProxyVlessConfig { line = line.split("vless://")[1]; let isShadowrocket; let parsed = /^(.*?)@(.*?):(\d+)\/?(\?(.*?))?(?:#(.*?))?$/.exec(line)!; @@ -428,9 +432,9 @@ function URI_VLESS(line: string): IProxyConfig { uuid = decodeURIComponent(uuid); name = decodeURIComponent(name); - const proxy: IProxyConfig = { + const proxy: IProxyVlessConfig = { type: "vless", - name, + name: "", server, port, uuid, @@ -444,14 +448,17 @@ function URI_VLESS(line: string): IProxyConfig { } proxy.name = - name ?? params.remarks ?? params.remark ?? `VLESS ${server}:${port}`; + trimStr(name) ?? + trimStr(params.remarks) ?? + trimStr(params.remark) ?? + `VLESS ${server}:${port}`; proxy.tls = (params.security && params.security !== "none") || undefined; if (isShadowrocket && /TRUE|1/i.test(params.tls)) { proxy.tls = true; params.security = params.security ?? "reality"; } - proxy.sni = params.sni || params.peer; + proxy.servername = params.sni || params.peer; proxy.flow = params.flow ? "xtls-rprx-vision" : undefined; proxy["client-fingerprint"] = params.fp as @@ -468,7 +475,7 @@ function URI_VLESS(line: string): IProxyConfig { proxy["skip-cert-verify"] = /(TRUE)|1/i.test(params.allowInsecure); if (["reality"].includes(params.security)) { - const opts: IProxyConfig["reality-opts"] = {}; + const opts: IProxyVlessConfig["reality-opts"] = {}; if (params.pbk) { opts["public-key"] = params.pbk; } @@ -481,18 +488,17 @@ function URI_VLESS(line: string): IProxyConfig { } let httpupgrade = false; - proxy.ws = { + proxy["ws-opts"] = { headers: undefined, - "ws-service-name": undefined, path: undefined, }; - proxy.http = { + + proxy["http-opts"] = { headers: undefined, - "http-service-name": undefined, path: undefined, }; - proxy.grpc = { "_grpc-type": undefined }; - proxy.network = params.type as "ws" | "http" | "h2" | "grpc"; + proxy["grpc-opts"] = {}; + if (params.headerType === "http") { proxy.network = "http"; } else { @@ -500,7 +506,22 @@ function URI_VLESS(line: string): IProxyConfig { httpupgrade = true; } if (!proxy.network && isShadowrocket && params.obfs) { - proxy.network = params.obfs as "ws" | "http" | "h2" | "grpc"; + switch (params.type) { + case "sw": + proxy.network = "ws"; + break; + case "http": + proxy.network = "http"; + break; + case "h2": + proxy.network = "h2"; + break; + case "grpc": + proxy.network = "grpc"; + break; + default: { + } + } } if (["websocket"].includes(proxy.network)) { proxy.network = "ws"; @@ -520,20 +541,9 @@ function URI_VLESS(line: string): IProxyConfig { opts.headers = { Host: host }; } } - if (params.serviceName) { - opts[`${proxy.network}-service-name`] = params.serviceName; - } else if (isShadowrocket && params.path) { - if (!["ws", "http", "h2"].includes(proxy.network)) { - opts[`${proxy.network}-service-name`] = params.path; - delete params.path; - } - } if (params.path) { opts.path = params.path; } - if (["grpc"].includes(proxy.network)) { - opts["_grpc-type"] = params.mode || "gun"; - } if (httpupgrade) { opts["v2ray-http-upgrade"] = true; opts["v2ray-http-upgrade-fast-open"] = true; @@ -543,25 +553,25 @@ function URI_VLESS(line: string): IProxyConfig { } } - if (proxy.tls && !proxy.sni) { + if (proxy.tls && !proxy.servername) { if (proxy.network === "ws") { - proxy.sni = proxy.ws?.headers?.Host; + proxy.servername = proxy["ws-opts"]?.headers?.Host; } else if (proxy.network === "http") { - let httpHost = proxy.http?.headers?.Host; - proxy.sni = Array.isArray(httpHost) ? httpHost[0] : httpHost; + let httpHost = proxy["http-opts"]?.headers?.Host; + proxy.servername = Array.isArray(httpHost) ? httpHost[0] : httpHost; } } return proxy; } -function URI_Trojan(line: string): IProxyConfig { +function URI_Trojan(line: string): IProxyTrojanConfig { let [newLine, name] = line.split(/#(.+)/, 2); const parser = getTrojanURIParser(); - const proxy = parser.parse(newLine); + const proxy: IProxyTrojanConfig = parser.parse(newLine); if (isNotBlank(name)) { try { - proxy.name = decodeURIComponent(name); + proxy.name = trimStr(decodeURIComponent(name)); } catch (e) { throw Error("Can not get proxy name"); } @@ -569,7 +579,7 @@ function URI_Trojan(line: string): IProxyConfig { return proxy; } -function URI_Hysteria2(line: string): IProxyConfig { +function URI_Hysteria2(line: string): IProxyHysteria2Config { line = line.split(/(hysteria2|hy2):\/\//)[2]; // eslint-disable-next-line no-unused-vars let [__, password, server, ___, port, ____, addons = "", name] = @@ -579,12 +589,12 @@ function URI_Hysteria2(line: string): IProxyConfig { portNum = 443; } password = decodeURIComponent(password); - if (name != null) { - name = decodeURIComponent(name); - } - name = name ?? `Hysteria2 ${server}:${port}`; - const proxy: IProxyConfig = { + let decodedName = trimStr(decodeURIComponent(name)); + + name = decodedName ?? `Hysteria2 ${server}:${port}`; + + const proxy: IProxyHysteria2Config = { type: "hysteria2", name, server, @@ -612,12 +622,12 @@ function URI_Hysteria2(line: string): IProxyConfig { proxy["obfs-password"] = params["obfs-password"]; proxy["skip-cert-verify"] = /(TRUE)|1/i.test(params.insecure); proxy.tfo = /(TRUE)|1/i.test(params.fastopen); - proxy["tls-fingerprint"] = params.pinSHA256; + proxy.fingerprint = params.pinSHA256; return proxy; } -function URI_Hysteria(line: string): IProxyConfig { +function URI_Hysteria(line: string): IProxyHysteriaConfig { line = line.split(/(hysteria|hy):\/\//)[2]; let [__, server, ___, port, ____, addons = "", name] = /^(.*?)(:(\d+))?\/?(\?(.*?))?(?:#(.*?))?$/.exec(line)!; @@ -625,12 +635,11 @@ function URI_Hysteria(line: string): IProxyConfig { if (isNaN(portNum)) { portNum = 443; } - if (name != null) { - name = decodeURIComponent(name); - } - name = name ?? `Hysteria ${server}:${port}`; + let decodedName = trimStr(decodeURIComponent(name)); - const proxy: IProxyConfig = { + name = decodedName ?? `Hysteria ${server}:${port}`; + + const proxy: IProxyHysteriaConfig = { type: "hysteria", name, server, @@ -713,7 +722,7 @@ function URI_Hysteria(line: string): IProxyConfig { return proxy; } -function URI_TUIC(line: string): IProxyConfig { +function URI_TUIC(line: string): IProxyTuicConfig { line = line.split(/tuic:\/\//)[1]; let [__, uuid, password, server, ___, port, ____, addons = "", name] = @@ -724,12 +733,11 @@ function URI_TUIC(line: string): IProxyConfig { portNum = 443; } password = decodeURIComponent(password); - if (name != null) { - name = decodeURIComponent(name); - } - name = name ?? `TUIC ${server}:${port}`; + let decodedName = trimStr(decodeURIComponent(name)); - const proxy: IProxyConfig = { + name = decodedName ?? `TUIC ${server}:${port}`; + + const proxy: IProxyTuicConfig = { type: "tuic", name, server, @@ -794,7 +802,7 @@ function URI_TUIC(line: string): IProxyConfig { return proxy; } -function URI_Wireguard(line: string): IProxyConfig { +function URI_Wireguard(line: string): IProxyWireguardConfig { line = line.split(/(wireguard|wg):\/\//)[2]; let [__, ___, privateKey, server, ____, port, _____, addons = "", name] = /^((.*?)@)?(.*?)(:(\d+))?\/?(\?(.*?))?(?:#(.*?))?$/.exec(line)!; @@ -804,11 +812,10 @@ function URI_Wireguard(line: string): IProxyConfig { portNum = 443; } privateKey = decodeURIComponent(privateKey); - if (name != null) { - name = decodeURIComponent(name); - } - name = name ?? `WireGuard ${server}:${port}`; - const proxy: IProxyConfig = { + let decodedName = trimStr(decodeURIComponent(name)); + + name = decodedName ?? `WireGuard ${server}:${port}`; + const proxy: IProxyWireguardConfig = { type: "wireguard", name, server, @@ -877,7 +884,7 @@ function URI_Wireguard(line: string): IProxyConfig { return proxy; } -function URI_HTTP(line: string): IProxyConfig { +function URI_HTTP(line: string): IProxyHttpConfig { line = line.split(/(http|https):\/\//)[2]; let [__, ___, auth, server, ____, port, _____, addons = "", name] = /^((.*?)@)?(.*?)(:(\d+))?\/?(\?(.*?))?(?:#(.*?))?$/.exec(line)!; @@ -889,11 +896,10 @@ function URI_HTTP(line: string): IProxyConfig { if (auth) { auth = decodeURIComponent(auth); } - if (name != null) { - name = decodeURIComponent(name); - } - name = name ?? `HTTP ${server}:${portNum}`; - const proxy: IProxyConfig = { + let decodedName = trimStr(decodeURIComponent(name)); + + name = decodedName ?? `HTTP ${server}:${portNum}`; + const proxy: IProxyHttpConfig = { type: "http", name, server, @@ -919,9 +925,6 @@ function URI_HTTP(line: string): IProxyConfig { case "skip-cert-verify": proxy["skip-cert-verify"] = /(TRUE)|1/i.test(value); break; - case "udp": - proxy["udp"] = /(TRUE)|1/i.test(value); - break; case "ip-version": proxy["ip-version"] = value; break; @@ -933,7 +936,7 @@ function URI_HTTP(line: string): IProxyConfig { return proxy; } -function URI_SOCKS(line: string): IProxyConfig { +function URI_SOCKS(line: string): IProxySocks5Config { line = line.split(/socks5:\/\//)[1]; let [__, ___, auth, server, ____, port, _____, addons = "", name] = /^((.*?)@)?(.*?)(:(\d+))?\/?(\?(.*?))?(?:#(.*?))?$/.exec(line)!; @@ -945,11 +948,9 @@ function URI_SOCKS(line: string): IProxyConfig { if (auth) { auth = decodeURIComponent(auth); } - if (name != null) { - name = decodeURIComponent(name); - } - name = name ?? `SOCKS5 ${server}:${portNum}`; - const proxy: IProxyConfig = { + let decodedName = trimStr(decodeURIComponent(name)); + name = decodedName ?? `SOCKS5 ${server}:${portNum}`; + const proxy: IProxySocks5Config = { type: "socks5", name, server,