1
0
mirror of https://github.com/bestnite/sub2clash.git synced 2025-11-03 20:30:35 +00:00

10 Commits

27 changed files with 449 additions and 163 deletions

3
.gitignore vendored
View File

@@ -6,3 +6,6 @@ logs
data
.env
.vscode/settings.json
config.yaml
config.yml
config.json

View File

@@ -154,7 +154,7 @@ func BuildSub(clashType model.ClashType, query model.SubConfig, template string,
return nil, NewRegexInvalidError("prefix", err)
}
if reg.Match(data) {
p, err := parser.ParseProxies(strings.Split(string(data), "\n")...)
p, err := parser.ParseProxies(parser.ParseConfig{UseUDP: query.UseUDP}, strings.Split(string(data), "\n")...)
if err != nil {
return nil, err
}
@@ -169,7 +169,7 @@ func BuildSub(clashType model.ClashType, query model.SubConfig, template string,
)
return nil, NewSubscriptionParseError(err)
}
p, err := parser.ParseProxies(strings.Split(base64, "\n")...)
p, err := parser.ParseProxies(parser.ParseConfig{UseUDP: query.UseUDP}, strings.Split(base64, "\n")...)
if err != nil {
return nil, err
}
@@ -187,7 +187,7 @@ func BuildSub(clashType model.ClashType, query model.SubConfig, template string,
}
if len(query.Proxy) != 0 {
p, err := parser.ParseProxies(query.Proxies...)
p, err := parser.ParseProxies(parser.ParseConfig{UseUDP: query.UseUDP}, query.Proxies...)
if err != nil {
return nil, err
}
@@ -200,6 +200,7 @@ func BuildSub(clashType model.ClashType, query model.SubConfig, template string,
}
}
// 去重
proxies := make(map[string]*P.Proxy)
newProxies := make([]P.Proxy, 0, len(proxyList))
for i := range proxyList {
@@ -216,6 +217,7 @@ func BuildSub(clashType model.ClashType, query model.SubConfig, template string,
}
proxyList = newProxies
// 移除
if strings.TrimSpace(query.Remove) != "" {
newProxyList := make([]P.Proxy, 0, len(proxyList))
for i := range proxyList {
@@ -233,8 +235,8 @@ func BuildSub(clashType model.ClashType, query model.SubConfig, template string,
proxyList = newProxyList
}
// 替换
if len(query.ReplaceKeys) != 0 {
replaceRegs := make([]*regexp.Regexp, 0, len(query.ReplaceKeys))
for _, v := range query.ReplaceKeys {
replaceReg, err := regexp.Compile(v)
@@ -256,6 +258,7 @@ func BuildSub(clashType model.ClashType, query model.SubConfig, template string,
}
}
// 重命名有相同名称的节点
names := make(map[string]int)
for i := range proxyList {
if _, exist := names[proxyList[i].Name]; exist {

View File

@@ -1,6 +1,10 @@
package proxy
import "fmt"
import (
"fmt"
"gopkg.in/yaml.v3"
)
type HTTPOptions struct {
Method string `yaml:"method,omitempty"`
@@ -144,7 +148,137 @@ func (p Proxy) MarshalYAML() (any, error) {
Name: p.Name,
Vmess: p.Vmess,
}, nil
case "socks5":
return struct {
Type string `yaml:"type"`
Name string `yaml:"name"`
Socks `yaml:",inline"`
}{
Type: p.Type,
Name: p.Name,
Socks: p.Socks,
}, nil
default:
return nil, fmt.Errorf("unsupported proxy type: %s", p.Type)
}
}
func (p *Proxy) UnmarshalYAML(node *yaml.Node) error {
var temp struct {
Type string `yaml:"type"`
Name string `yaml:"name"`
}
if err := node.Decode(&temp); err != nil {
return err
}
p.Type = temp.Type
p.Name = temp.Name
switch temp.Type {
case "anytls":
var data struct {
Type string `yaml:"type"`
Name string `yaml:"name"`
Anytls `yaml:",inline"`
}
if err := node.Decode(&data); err != nil {
return err
}
p.Anytls = data.Anytls
case "hysteria":
var data struct {
Type string `yaml:"type"`
Name string `yaml:"name"`
Hysteria `yaml:",inline"`
}
if err := node.Decode(&data); err != nil {
return err
}
p.Hysteria = data.Hysteria
case "hysteria2":
var data struct {
Type string `yaml:"type"`
Name string `yaml:"name"`
Hysteria2 `yaml:",inline"`
}
if err := node.Decode(&data); err != nil {
return err
}
p.Hysteria2 = data.Hysteria2
case "ss":
var data struct {
Type string `yaml:"type"`
Name string `yaml:"name"`
ShadowSocks `yaml:",inline"`
}
if err := node.Decode(&data); err != nil {
return err
}
p.ShadowSocks = data.ShadowSocks
case "ssr":
var data struct {
Type string `yaml:"type"`
Name string `yaml:"name"`
ShadowSocksR `yaml:",inline"`
}
if err := node.Decode(&data); err != nil {
return err
}
p.ShadowSocksR = data.ShadowSocksR
case "trojan":
var data struct {
Type string `yaml:"type"`
Name string `yaml:"name"`
Trojan `yaml:",inline"`
}
if err := node.Decode(&data); err != nil {
return err
}
p.Trojan = data.Trojan
case "vless":
var data struct {
Type string `yaml:"type"`
Name string `yaml:"name"`
Vless `yaml:",inline"`
}
if err := node.Decode(&data); err != nil {
return err
}
p.Vless = data.Vless
case "vmess":
var data struct {
Type string `yaml:"type"`
Name string `yaml:"name"`
Vmess `yaml:",inline"`
}
if err := node.Decode(&data); err != nil {
return err
}
p.Vmess = data.Vmess
case "socks5":
var data struct {
Type string `yaml:"type"`
Name string `yaml:"name"`
Socks `yaml:",inline"`
}
if err := node.Decode(&data); err != nil {
return err
}
p.Socks = data.Socks
default:
return fmt.Errorf("unsupported proxy type: %s", temp.Type)
}
return nil
}

View File

@@ -32,6 +32,7 @@ type SubConfig struct {
NodeListMode bool `form:"nodeList,default=false" binding:""`
IgnoreCountryGrooup bool `form:"ignoreCountryGroup,default=false" binding:""`
UserAgent string `form:"userAgent" binding:""`
UseUDP bool `form:"useUDP,default=false" binding:""`
}
type RuleProviderStruct struct {

View File

@@ -26,7 +26,7 @@ func (p *AnytlsParser) GetType() string {
return "anytls"
}
func (p *AnytlsParser) Parse(proxy string) (P.Proxy, error) {
func (p *AnytlsParser) Parse(config ParseConfig, proxy string) (P.Proxy, error) {
if !hasPrefix(proxy, p.GetPrefixes()) {
return P.Proxy{}, fmt.Errorf("%w: %s", ErrInvalidPrefix, proxy)
}
@@ -72,6 +72,7 @@ func (p *AnytlsParser) Parse(proxy string) (P.Proxy, error) {
Password: password,
SNI: sni,
SkipCertVerify: insecureBool,
UDP: config.UseUDP,
},
}
return result, nil

View File

@@ -5,6 +5,7 @@ import (
"errors"
"strconv"
"strings"
"unicode/utf8"
P "github.com/bestnite/sub2clash/model/proxy"
)
@@ -32,8 +33,13 @@ func ParsePort(portStr string) (int, error) {
return port, nil
}
// isLikelyBase64 不严格判断是否是合法的 Base64, 很多分享链接不符合 Base64 规范
func isLikelyBase64(s string) bool {
if len(s)%4 == 0 && strings.HasSuffix(s, "=") && !strings.Contains(strings.TrimSuffix(s, "="), "=") {
if strings.TrimSpace(s) == "" {
return false
}
if !strings.Contains(strings.TrimSuffix(s, "="), "=") {
s = strings.TrimSuffix(s, "=")
chars := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
for _, c := range s {
@@ -41,17 +47,25 @@ func isLikelyBase64(s string) bool {
return false
}
}
return true
}
decoded, err := DecodeBase64(s)
if err != nil {
return false
}
if !utf8.ValidString(decoded) {
return false
}
return true
}
func DecodeBase64(s string) (string, error) {
s = strings.TrimSpace(s)
if strings.Contains(s, "-") || strings.Contains(s, "_") {
s = strings.Replace(s, "-", "+", -1)
s = strings.Replace(s, "_", "/", -1)
s = strings.ReplaceAll(s, "-", "+")
s = strings.ReplaceAll(s, "_", "/")
}
if len(s)%4 != 0 {
s += strings.Repeat("=", 4-len(s)%4)
@@ -63,14 +77,18 @@ func DecodeBase64(s string) (string, error) {
return string(decodeStr), nil
}
func ParseProxies(proxies ...string) ([]P.Proxy, error) {
type ParseConfig struct {
UseUDP bool
}
func ParseProxies(config ParseConfig, proxies ...string) ([]P.Proxy, error) {
var result []P.Proxy
for _, proxy := range proxies {
if proxy != "" {
var proxyItem P.Proxy
var err error
proxyItem, err = ParseProxyWithRegistry(proxy)
proxyItem, err = ParseProxyWithRegistry(config, proxy)
if err != nil {
return nil, err
}

View File

@@ -27,7 +27,7 @@ func (p *HysteriaParser) GetType() string {
return "hysteria"
}
func (p *HysteriaParser) Parse(proxy string) (P.Proxy, error) {
func (p *HysteriaParser) Parse(config ParseConfig, proxy string) (P.Proxy, error) {
if !hasPrefix(proxy, p.GetPrefixes()) {
return P.Proxy{}, fmt.Errorf("%w: %s", ErrInvalidPrefix, proxy)
}

View File

@@ -26,7 +26,7 @@ func (p *Hysteria2Parser) GetType() string {
return "hysteria2"
}
func (p *Hysteria2Parser) Parse(proxy string) (P.Proxy, error) {
func (p *Hysteria2Parser) Parse(config ParseConfig, proxy string) (P.Proxy, error) {
if !hasPrefix(proxy, p.GetPrefixes()) {
return P.Proxy{}, fmt.Errorf("%w: %s", ErrInvalidPrefix, proxy)
}

View File

@@ -9,7 +9,7 @@ import (
)
type ProxyParser interface {
Parse(proxy string) (P.Proxy, error)
Parse(config ParseConfig, proxy string) (P.Proxy, error)
GetPrefixes() []string
GetType() string
SupportClash() bool
@@ -64,7 +64,7 @@ func GetAllPrefixes() []string {
return prefixes
}
func ParseProxyWithRegistry(proxy string) (P.Proxy, error) {
func ParseProxyWithRegistry(config ParseConfig, proxy string) (P.Proxy, error) {
proxy = strings.TrimSpace(proxy)
if proxy == "" {
return P.Proxy{}, fmt.Errorf("%w: %s", ErrInvalidStruct, "empty proxy string")
@@ -72,7 +72,7 @@ func ParseProxyWithRegistry(proxy string) (P.Proxy, error) {
for prefix, parser := range registry.parsers {
if strings.HasPrefix(proxy, prefix) {
return parser.Parse(proxy)
return parser.Parse(config, proxy)
}
}

View File

@@ -30,7 +30,7 @@ func (p *ShadowsocksParser) GetType() string {
}
// Parse 解析Shadowsocks代理
func (p *ShadowsocksParser) Parse(proxy string) (P.Proxy, error) {
func (p *ShadowsocksParser) Parse(config ParseConfig, proxy string) (P.Proxy, error) {
if !hasPrefix(proxy, p.GetPrefixes()) {
return P.Proxy{}, fmt.Errorf("%w: %s", ErrInvalidPrefix, proxy)
}
@@ -108,9 +108,9 @@ func (p *ShadowsocksParser) Parse(proxy string) (P.Proxy, error) {
Password: password,
Server: server,
Port: port,
UDP: config.UseUDP,
},
}
return result, nil
}

View File

@@ -27,7 +27,7 @@ func (p *ShadowsocksRParser) GetType() string {
return "ssr"
}
func (p *ShadowsocksRParser) Parse(proxy string) (P.Proxy, error) {
func (p *ShadowsocksRParser) Parse(config ParseConfig, proxy string) (P.Proxy, error) {
if !hasPrefix(proxy, p.GetPrefixes()) {
return P.Proxy{}, fmt.Errorf("%w: %s", ErrInvalidPrefix, proxy)
}
@@ -100,9 +100,9 @@ func (p *ShadowsocksRParser) Parse(proxy string) (P.Proxy, error) {
Password: password,
ObfsParam: obfsParam,
ProtocolParam: protoParam,
UDP: config.UseUDP,
},
}
return result, nil
}

View File

@@ -18,14 +18,14 @@ func (p *SocksParser) SupportMeta() bool {
}
func (p *SocksParser) GetPrefixes() []string {
return []string{"socks://"}
return []string{"socks://", "socks5://"}
}
func (p *SocksParser) GetType() string {
return "socks5"
}
func (p *SocksParser) Parse(proxy string) (P.Proxy, error) {
func (p *SocksParser) Parse(config ParseConfig, proxy string) (P.Proxy, error) {
if !hasPrefix(proxy, p.GetPrefixes()) {
return P.Proxy{}, fmt.Errorf("%w: %s", ErrInvalidPrefix, proxy)
}

View File

@@ -26,7 +26,7 @@ func (p *TrojanParser) GetType() string {
return "trojan"
}
func (p *TrojanParser) Parse(proxy string) (P.Proxy, error) {
func (p *TrojanParser) Parse(config ParseConfig, proxy string) (P.Proxy, error) {
if !hasPrefix(proxy, p.GetPrefixes()) {
return P.Proxy{}, fmt.Errorf("%w: %s", ErrInvalidPrefix, proxy)
}
@@ -58,7 +58,17 @@ func (p *TrojanParser) Parse(proxy string) (P.Proxy, error) {
remarks = strings.TrimSpace(remarks)
query := link.Query()
network, security, alpnStr, sni, pbk, sid, fp, path, host, serviceName, udp := query.Get("type"), query.Get("security"), query.Get("alpn"), query.Get("sni"), query.Get("pbk"), query.Get("sid"), query.Get("fp"), query.Get("path"), query.Get("host"), query.Get("serviceName"), query.Get("udp")
network, security, alpnStr, sni, pbk, sid, fp, path, host, serviceName, udp, insecure := query.Get("type"), query.Get("security"), query.Get("alpn"), query.Get("sni"), query.Get("pbk"), query.Get("sid"), query.Get("fp"), query.Get("path"), query.Get("host"), query.Get("serviceName"), query.Get("udp"), query.Get("allowInsecure")
insecureBool := insecure == "1"
result := P.Trojan{
Server: server,
Port: port,
Password: password,
Network: network,
UDP: udp == "true",
SkipCertVerify: insecureBool,
}
var alpn []string
if strings.Contains(alpnStr, ",") {
@@ -66,27 +76,23 @@ func (p *TrojanParser) Parse(proxy string) (P.Proxy, error) {
} else {
alpn = nil
}
result := P.Trojan{
Server: server,
Port: port,
Password: password,
Network: network,
UDP: udp == "true",
if len(alpn) > 0 {
result.ALPN = alpn
}
if security == "xtls" || security == "tls" {
result.ALPN = alpn
if fp != "" {
result.ClientFingerprint = fp
}
if sni != "" {
result.SNI = sni
}
if security == "reality" {
result.SNI = sni
result.RealityOpts = P.RealityOptions{
PublicKey: pbk,
ShortID: sid,
}
result.Fingerprint = fp
}
if network == "ws" {

View File

@@ -26,7 +26,7 @@ func (p *VlessParser) GetType() string {
return "vless"
}
func (p *VlessParser) Parse(proxy string) (P.Proxy, error) {
func (p *VlessParser) Parse(config ParseConfig, proxy string) (P.Proxy, error) {
if !hasPrefix(proxy, p.GetPrefixes()) {
return P.Proxy{}, fmt.Errorf("%w: %s", ErrInvalidPrefix, proxy)
}
@@ -57,6 +57,7 @@ func (p *VlessParser) Parse(proxy string) (P.Proxy, error) {
} else {
alpn = nil
}
remarks := link.Fragment
if remarks == "" {
remarks = fmt.Sprintf("%s:%s", server, portStr)
@@ -69,24 +70,31 @@ func (p *VlessParser) Parse(proxy string) (P.Proxy, error) {
UUID: uuid,
Flow: flow,
UDP: udp == "true",
SkipCertVerify: insecureBool,
}
if len(alpn) > 0 {
result.ALPN = alpn
}
if fp != "" {
result.ClientFingerprint = fp
}
if sni != "" {
result.ServerName = sni
}
if security == "tls" {
result.TLS = true
result.ALPN = alpn
result.SkipCertVerify = insecureBool
result.Fingerprint = fp
result.ServerName = sni
}
if security == "reality" {
result.TLS = true
result.ServerName = sni
result.RealityOpts = P.RealityOptions{
PublicKey: pbk,
ShortID: sid,
}
result.Fingerprint = fp
}
if _type == "ws" {

View File

@@ -46,7 +46,7 @@ func (p *VmessParser) GetType() string {
return "vmess"
}
func (p *VmessParser) Parse(proxy string) (P.Proxy, error) {
func (p *VmessParser) Parse(config ParseConfig, proxy string) (P.Proxy, error) {
if !hasPrefix(proxy, p.GetPrefixes()) {
return P.Proxy{}, fmt.Errorf("%w: %s", ErrInvalidPrefix, proxy)
}
@@ -99,27 +99,38 @@ func (p *VmessParser) Parse(proxy string) (P.Proxy, error) {
name = vmess.Ps
}
result := P.Vmess{
Server: vmess.Add,
Port: port,
UUID: vmess.Id,
AlterID: aid,
Cipher: vmess.Scy,
}
if vmess.Tls == "tls" {
var alpn []string
if strings.Contains(vmess.Alpn, ",") {
alpn = strings.Split(vmess.Alpn, ",")
} else {
alpn = nil
}
result.TLS = true
result.Fingerprint = vmess.Fp
result := P.Vmess{
Server: vmess.Add,
Port: port,
UUID: vmess.Id,
AlterID: aid,
Cipher: vmess.Scy,
UDP: config.UseUDP,
}
if len(alpn) > 0 {
result.ALPN = alpn
}
if vmess.Fp != "" {
result.ClientFingerprint = vmess.Fp
}
if vmess.Sni != "" {
result.ServerName = vmess.Sni
}
if vmess.Tls == "tls" {
result.TLS = true
}
if vmess.Net == "ws" {
if vmess.Path == "" {
vmess.Path = "/"

View File

@@ -1,6 +1,7 @@
package handler
import (
"fmt"
"io"
"net/http"
"strings"
@@ -168,7 +169,19 @@ func GetRawConfHandler(c *gin.Context) {
return
}
response, err := http.Get(strings.TrimSuffix(config.GlobalConfig.Address, "/") + "/" + shortLink.Url)
scheme := "http"
if c.Request.TLS != nil {
scheme = "https"
}
host := c.Request.Host
targetPath := strings.TrimPrefix(shortLink.Url, "/")
requestURL := fmt.Sprintf("%s://%s/%s", scheme, host, targetPath)
client := &http.Client{
Timeout: 30 * time.Second, // 30秒超时
}
response, err := client.Get(requestURL)
if err != nil {
respondWithError(c, http.StatusInternalServerError, "请求错误: "+err.Error())
return

View File

@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="zh-CN">
<html lang="zh-CN" data-bs-theme="light">
<head>
<meta charset="UTF-8" />
@@ -28,10 +28,38 @@
height: 25px;
width: 25px;
}
/* 主题切换按钮样式 */
.theme-toggle {
position: fixed;
top: 20px;
right: 20px;
z-index: 1000;
border: none;
border-radius: 50%;
width: 50px;
height: 50px;
font-size: 20px;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.3s ease;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
}
.theme-toggle:hover {
transform: scale(1.1);
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
}
</style>
</head>
<body class="bg-light">
<body>
<!-- 主题切换按钮 -->
<button class="theme-toggle btn btn-outline-secondary" onclick="toggleTheme()" title="切换深色/浅色模式">
<span id="theme-icon">🌙</span>
</button>
<div class="container mt-5">
<div class="mb-4">
<h2>sub2clash</h2>
@@ -55,7 +83,7 @@
<label for="endpoint">客户端类型:</label>
<select class="form-control" id="endpoint" name="endpoint">
<option value="clash">Clash</option>
<option value="meta">Clash.Meta</option>
<option value="meta" selected>Clash.Meta</option>
</select>
</div>
<!-- Template -->
@@ -75,9 +103,9 @@
</div>
<!-- User Agent -->
<div class="form-group mb-3">
<label for="user-agent">ua标识:</label>
<label for="user-agent">UA 标识:</label>
<textarea class="form-control" id="user-agent" name="user-agent"
placeholder="用于获取订阅的http请求中的user-agent标识(可选)" rows="3"></textarea>
placeholder="用于获取订阅的 http 请求中的 User-Agent 标识可选" rows="3"></textarea>
</div>
<!-- Refresh -->
<div class="form-check mb-3">
@@ -104,6 +132,11 @@
<input class="form-check-input" id="igcg" name="igcg" type="checkbox" />
<label class="form-check-label" for="igcg">不输出国家策略组</label>
</div>
<!-- Use UDP -->
<div class="form-check mb-3">
<input class="form-check-input" id="useUDP" name="useUDP" type="checkbox" />
<label class="form-check-label" for="useUDP">使用 UDP</label>
</div>
<!-- Rule Provider -->
<div class="form-group mb-3" id="ruleProviderGroup">
<label>Rule Provider:</label>
@@ -145,7 +178,7 @@
<div class="form-group mb-5">
<label for="apiLink">配置链接:</label>
<div class="input-group mb-2">
<input class="form-control bg-light" id="apiLink" type="text" placeholder="链接" readonly
<input class="form-control" id="apiLink" type="text" placeholder="链接" readonly
style="cursor: not-allowed;" />
<button class="btn btn-primary" onclick="copyToClipboard('apiLink',this)" type="button">
复制链接
@@ -162,7 +195,7 @@
</button>
</div>
<div class="input-group">
<input class="form-control bg-light" id="apiShortLink" type="text" placeholder="短链接" readonly
<input class="form-control" id="apiShortLink" type="text" placeholder="短链接" readonly
style="cursor: not-allowed;" />
<button class="btn btn-primary" onclick="updateShortLink()" type="button">
更新短链

View File

@@ -1,11 +1,9 @@
function setInputReadOnly(input, readonly) {
if (readonly) {
input.readOnly = true;
input.classList.add('bg-light');
input.style.cursor = 'not-allowed';
} else {
input.readOnly = false;
input.classList.remove('bg-light');
input.style.cursor = 'auto';
}
}
@@ -19,6 +17,7 @@ function clearExistingValues() {
document.getElementById("autoTest").checked = false;
document.getElementById("lazy").checked = false;
document.getElementById("igcg").checked = false;
document.getElementById("useUDP").checked = false;
document.getElementById("template").value = "";
document.getElementById("sort").value = "nameasc";
document.getElementById("remove").value = "";
@@ -110,6 +109,8 @@ function generateURI() {
queryParams.push(`nodeList=${nodeList ? "true" : "false"}`);
const igcg = document.getElementById("igcg").checked;
queryParams.push(`ignoreCountryGroup=${igcg ? "true" : "false"}`);
const useUDP = document.getElementById("useUDP").checked;
queryParams.push(`useUDP=${useUDP ? "true" : "false"}`);
// 获取模板链接或名称(如果存在)
const template = document.getElementById("template").value;
@@ -336,6 +337,11 @@ async function parseInputURL() {
document.getElementById("nodeList").checked =
params.get("nodeList") === "true";
}
if (params.has("useUDP")) {
document.getElementById("useUDP").checked =
params.get("useUDP") === "true";
}
}
function clearInputGroup(groupId) {
@@ -580,4 +586,53 @@ function updateShortLink() {
});
}
// 主题切换功能
function initTheme() {
const html = document.querySelector('html');
const themeIcon = document.getElementById('theme-icon');
let theme;
// 从localStorage获取用户偏好的主题
const savedTheme = localStorage.getItem('theme');
if (savedTheme) {
// 如果用户之前设置过主题,使用保存的主题
theme = savedTheme;
} else {
// 如果没有设置过,检测系统主题偏好
const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
theme = prefersDark ? 'dark' : 'light';
}
// 设置主题
html.setAttribute('data-bs-theme', theme);
// 更新图标
if (theme === 'dark') {
themeIcon.textContent = '☀️';
} else {
themeIcon.textContent = '🌙';
}
}
function toggleTheme() {
const html = document.querySelector('html');
const currentTheme = html.getAttribute('data-bs-theme');
// 切换主题
const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
html.setAttribute('data-bs-theme', newTheme);
// 更新图标
if (newTheme === 'dark') {
themeIcon.textContent = '☀️';
} else {
themeIcon.textContent = '🌙';
}
// 保存用户偏好到localStorage
localStorage.setItem('theme', newTheme);
}
listenInput();
initTheme();

View File

@@ -22,7 +22,7 @@ func TestAnytls_Basic_SimpleLink(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -47,7 +47,7 @@ func TestAnytls_Basic_WithSNI(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -72,7 +72,7 @@ func TestAnytls_Basic_WithInsecure(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -96,7 +96,7 @@ func TestAnytls_Basic_IPv6Address(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -121,7 +121,7 @@ func TestAnytls_Basic_ComplexPassword(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -145,7 +145,7 @@ func TestAnytls_Basic_NoPassword(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -169,7 +169,7 @@ func TestAnytls_Basic_UsernameOnly(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -182,7 +182,7 @@ func TestAnytls_Error_MissingServer(t *testing.T) {
p := &parser.AnytlsParser{}
input := "anytls://password123@:8080"
_, err := p.Parse(input)
_, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err == nil {
t.Errorf("Expected error but got none")
}
@@ -192,7 +192,7 @@ func TestAnytls_Error_MissingPort(t *testing.T) {
p := &parser.AnytlsParser{}
input := "anytls://password123@127.0.0.1"
_, err := p.Parse(input)
_, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err == nil {
t.Errorf("Expected error but got none")
}
@@ -202,7 +202,7 @@ func TestAnytls_Error_InvalidPort(t *testing.T) {
p := &parser.AnytlsParser{}
input := "anytls://password123@127.0.0.1:99999"
_, err := p.Parse(input)
_, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err == nil {
t.Errorf("Expected error but got none")
}
@@ -212,7 +212,7 @@ func TestAnytls_Error_InvalidProtocol(t *testing.T) {
p := &parser.AnytlsParser{}
input := "anyssl://example.com:8080"
_, err := p.Parse(input)
_, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err == nil {
t.Errorf("Expected error but got none")
}

View File

@@ -22,7 +22,7 @@ func TestHysteria2_Basic_SimpleLink(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -47,7 +47,7 @@ func TestHysteria2_Basic_AltPrefix(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -73,7 +73,7 @@ func TestHysteria2_Basic_WithObfs(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -97,7 +97,7 @@ func TestHysteria2_Basic_IPv6Address(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -124,7 +124,7 @@ func TestHysteria2_Basic_FullConfig(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -148,7 +148,7 @@ func TestHysteria2_Basic_NoPassword(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -161,7 +161,7 @@ func TestHysteria2_Error_MissingServer(t *testing.T) {
p := &parser.Hysteria2Parser{}
input := "hysteria2://password123@:8080"
_, err := p.Parse(input)
_, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err == nil {
t.Errorf("Expected error but got none")
}
@@ -171,7 +171,7 @@ func TestHysteria2_Error_MissingPort(t *testing.T) {
p := &parser.Hysteria2Parser{}
input := "hysteria2://password123@127.0.0.1"
_, err := p.Parse(input)
_, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err == nil {
t.Errorf("Expected error but got none")
}
@@ -181,7 +181,7 @@ func TestHysteria2_Error_InvalidPort(t *testing.T) {
p := &parser.Hysteria2Parser{}
input := "hysteria2://password123@127.0.0.1:99999"
_, err := p.Parse(input)
_, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err == nil {
t.Errorf("Expected error but got none")
}
@@ -191,7 +191,7 @@ func TestHysteria2_Error_InvalidProtocol(t *testing.T) {
p := &parser.Hysteria2Parser{}
input := "hysteria://example.com:8080"
_, err := p.Parse(input)
_, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err == nil {
t.Errorf("Expected error but got none")
}

View File

@@ -25,7 +25,7 @@ func TestHysteria_Basic_SimpleLink(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -52,7 +52,7 @@ func TestHysteria_Basic_WithAuthString(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -80,7 +80,7 @@ func TestHysteria_Basic_WithObfs(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -106,7 +106,7 @@ func TestHysteria_Basic_IPv6Address(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -133,7 +133,7 @@ func TestHysteria_Basic_MultiALPN(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -146,7 +146,7 @@ func TestHysteria_Error_MissingServer(t *testing.T) {
p := &parser.HysteriaParser{}
input := "hysteria://:8080?auth=password123"
_, err := p.Parse(input)
_, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err == nil {
t.Errorf("Expected error but got none")
}
@@ -156,7 +156,7 @@ func TestHysteria_Error_MissingPort(t *testing.T) {
p := &parser.HysteriaParser{}
input := "hysteria://127.0.0.1?auth=password123"
_, err := p.Parse(input)
_, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err == nil {
t.Errorf("Expected error but got none")
}
@@ -166,7 +166,7 @@ func TestHysteria_Error_InvalidPort(t *testing.T) {
p := &parser.HysteriaParser{}
input := "hysteria://127.0.0.1:99999?auth=password123"
_, err := p.Parse(input)
_, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err == nil {
t.Errorf("Expected error but got none")
}
@@ -176,7 +176,7 @@ func TestHysteria_Error_InvalidProtocol(t *testing.T) {
p := &parser.HysteriaParser{}
input := "hysteria2://example.com:8080"
_, err := p.Parse(input)
_, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err == nil {
t.Errorf("Expected error but got none")
}

View File

@@ -23,7 +23,7 @@ func TestShadowsocks_Basic_SimpleLink(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -47,7 +47,7 @@ func TestShadowsocks_Basic_IPv6Address(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -71,7 +71,7 @@ func TestShadowsocks_Basic_WithRemark(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -95,7 +95,7 @@ func TestShadowsocks_Advanced_Base64FullEncoded(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -119,7 +119,7 @@ func TestShadowsocks_Advanced_PlainUserPassword(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -143,7 +143,7 @@ func TestShadowsocks_Advanced_ChaCha20Cipher(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -157,7 +157,7 @@ func TestShadowsocks_Error_MissingServer(t *testing.T) {
p := &parser.ShadowsocksParser{}
input := "ss://YWVzLTI1Ni1nY206cGFzc3dvcmQ=@:8080"
_, err := p.Parse(input)
_, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if !errors.Is(err, parser.ErrInvalidStruct) {
t.Errorf("Error is not expected: %v", err)
}
@@ -167,7 +167,7 @@ func TestShadowsocks_Error_MissingPort(t *testing.T) {
p := &parser.ShadowsocksParser{}
input := "ss://YWVzLTI1Ni1nY206cGFzc3dvcmQ=@127.0.0.1"
_, err := p.Parse(input)
_, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if !errors.Is(err, parser.ErrInvalidStruct) {
t.Errorf("Error is not expected: %v", err)
}
@@ -177,7 +177,7 @@ func TestShadowsocks_Error_InvalidProtocol(t *testing.T) {
p := &parser.ShadowsocksParser{}
input := "http://example.com:8080"
_, err := p.Parse(input)
_, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if !errors.Is(err, parser.ErrInvalidPrefix) {
t.Errorf("Error is not expected: %v", err)
}

View File

@@ -26,7 +26,7 @@ func TestShadowsocksR_Basic_SimpleLink(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -54,7 +54,7 @@ func TestShadowsocksR_Basic_WithParams(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -82,7 +82,7 @@ func TestShadowsocksR_Basic_IPv6Address(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -95,7 +95,7 @@ func TestShadowsocksR_Error_InvalidBase64(t *testing.T) {
p := &parser.ShadowsocksRParser{}
input := "ssr://invalid_base64"
_, err := p.Parse(input)
_, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err == nil {
t.Errorf("Expected error but got none")
}
@@ -105,7 +105,7 @@ func TestShadowsocksR_Error_InvalidProtocol(t *testing.T) {
p := &parser.ShadowsocksRParser{}
input := "ss://example.com:8080"
_, err := p.Parse(input)
_, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err == nil {
t.Errorf("Expected error but got none")
}

View File

@@ -22,7 +22,7 @@ func TestSocks_Basic_SimpleLink(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -44,7 +44,7 @@ func TestSocks_Basic_NoAuth(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -68,7 +68,7 @@ func TestSocks_Basic_IPv6Address(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -93,7 +93,7 @@ func TestSocks_Basic_WithTLS(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -118,7 +118,7 @@ func TestSocks_Basic_WithUDP(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -131,7 +131,7 @@ func TestSocks_Error_MissingServer(t *testing.T) {
p := &parser.SocksParser{}
input := "socks://user:pass@:1080"
_, err := p.Parse(input)
_, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err == nil {
t.Errorf("Expected error but got none")
}
@@ -141,7 +141,7 @@ func TestSocks_Error_MissingPort(t *testing.T) {
p := &parser.SocksParser{}
input := "socks://user:pass@127.0.0.1"
_, err := p.Parse(input)
_, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err == nil {
t.Errorf("Expected error but got none")
}
@@ -151,7 +151,7 @@ func TestSocks_Error_InvalidPort(t *testing.T) {
p := &parser.SocksParser{}
input := "socks://user:pass@127.0.0.1:99999"
_, err := p.Parse(input)
_, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err == nil {
t.Errorf("Expected error but got none")
}
@@ -161,7 +161,7 @@ func TestSocks_Error_InvalidProtocol(t *testing.T) {
p := &parser.SocksParser{}
input := "ss://example.com:8080"
_, err := p.Parse(input)
_, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err == nil {
t.Errorf("Expected error but got none")
}

View File

@@ -21,7 +21,7 @@ func TestTrojan_Basic_SimpleLink(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -46,7 +46,7 @@ func TestTrojan_Basic_WithTLS(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -75,7 +75,7 @@ func TestTrojan_Basic_WithReality(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -105,7 +105,7 @@ func TestTrojan_Basic_WithWebSocket(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -132,7 +132,7 @@ func TestTrojan_Basic_WithGrpc(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -145,7 +145,7 @@ func TestTrojan_Error_MissingServer(t *testing.T) {
p := &parser.TrojanParser{}
input := "trojan://password@:443"
_, err := p.Parse(input)
_, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err == nil {
t.Errorf("Expected error but got none")
}
@@ -155,7 +155,7 @@ func TestTrojan_Error_MissingPort(t *testing.T) {
p := &parser.TrojanParser{}
input := "trojan://password@127.0.0.1"
_, err := p.Parse(input)
_, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err == nil {
t.Errorf("Expected error but got none")
}
@@ -165,7 +165,7 @@ func TestTrojan_Error_InvalidPort(t *testing.T) {
p := &parser.TrojanParser{}
input := "trojan://password@127.0.0.1:99999"
_, err := p.Parse(input)
_, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err == nil {
t.Errorf("Expected error but got none")
}
@@ -175,7 +175,7 @@ func TestTrojan_Error_InvalidProtocol(t *testing.T) {
p := &parser.TrojanParser{}
input := "ss://example.com:8080"
_, err := p.Parse(input)
_, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err == nil {
t.Errorf("Expected error but got none")
}

View File

@@ -21,7 +21,7 @@ func TestVless_Basic_SimpleLink(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -47,7 +47,7 @@ func TestVless_Basic_WithTLS(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -77,7 +77,7 @@ func TestVless_Basic_WithReality(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -107,7 +107,7 @@ func TestVless_Basic_WithWebSocket(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -134,7 +134,7 @@ func TestVless_Basic_WithGrpc(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -164,7 +164,7 @@ func TestVless_Basic_WithHTTP(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -177,7 +177,7 @@ func TestVless_Error_MissingServer(t *testing.T) {
p := &parser.VlessParser{}
input := "vless://b831b0c4-33b7-4873-9834-28d66d87d4ce@:8080"
_, err := p.Parse(input)
_, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err == nil {
t.Errorf("Expected error but got none")
}
@@ -187,7 +187,7 @@ func TestVless_Error_MissingPort(t *testing.T) {
p := &parser.VlessParser{}
input := "vless://b831b0c4-33b7-4873-9834-28d66d87d4ce@127.0.0.1"
_, err := p.Parse(input)
_, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err == nil {
t.Errorf("Expected error but got none")
}
@@ -197,7 +197,7 @@ func TestVless_Error_InvalidPort(t *testing.T) {
p := &parser.VlessParser{}
input := "vless://b831b0c4-33b7-4873-9834-28d66d87d4ce@127.0.0.1:99999"
_, err := p.Parse(input)
_, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err == nil {
t.Errorf("Expected error but got none")
}
@@ -207,7 +207,7 @@ func TestVless_Error_InvalidProtocol(t *testing.T) {
p := &parser.VlessParser{}
input := "ss://example.com:8080"
_, err := p.Parse(input)
_, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err == nil {
t.Errorf("Expected error but got none")
}

View File

@@ -31,7 +31,7 @@ func TestVmess_Basic_SimpleLink(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -64,7 +64,7 @@ func TestVmess_Basic_WithPath(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -97,7 +97,7 @@ func TestVmess_Basic_WithHost(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -131,7 +131,7 @@ func TestVmess_Basic_WithSNI(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -164,7 +164,7 @@ func TestVmess_Basic_WithAlterID(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -192,7 +192,7 @@ func TestVmess_Basic_GRPC(t *testing.T) {
},
}
result, err := p.Parse(input)
result, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err != nil {
t.Errorf("Unexpected error: %v", err)
return
@@ -205,7 +205,7 @@ func TestVmess_Error_InvalidBase64(t *testing.T) {
p := &parser.VmessParser{}
input := "vmess://invalid_base64"
_, err := p.Parse(input)
_, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err == nil {
t.Errorf("Expected error but got none")
}
@@ -215,7 +215,7 @@ func TestVmess_Error_InvalidJSON(t *testing.T) {
p := &parser.VmessParser{}
input := "vmess://eyJpbnZhbGlkIjoianNvbn0="
_, err := p.Parse(input)
_, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err == nil {
t.Errorf("Expected error but got none")
}
@@ -225,7 +225,7 @@ func TestVmess_Error_InvalidProtocol(t *testing.T) {
p := &parser.VmessParser{}
input := "ss://example.com:8080"
_, err := p.Parse(input)
_, err := p.Parse(parser.ParseConfig{UseUDP: false}, input)
if err == nil {
t.Errorf("Expected error but got none")
}